Giter VIP home page Giter VIP logo

blog's Introduction

blog's People

Contributors

majianyang666 avatar

Watchers

James Cloos avatar  avatar

blog's Issues

同源和跨域

运行方式

  1. 伪装一个网站(在本地)

    1.1 编辑 hosts 文件

    • mac: sudo vi /etc/hosts
    • windows: 用以管理员身份运行 git bash,vi C:/Windows/System32/drivers/etcetc/hosts

    1.2. 添加两行
    127.0.0.1 qq.com
    127.0.0.1 frank.com

    1.3. 保存关闭

  2. 监听 80 端口

    • Mac:sudo http-server -c-1 -p 80

    • Windows:

    1. 以管理员身份运行 git bash
    2. http-server -c-1 -p 80

浏览器的同源策略

同域名(或ip),同端口,同协议视为同一个域,一个域内的脚本仅仅具有本域内的权限,可以理解为本域脚本只能读写本域内的资源,而无法访问其它域的资源。这种安全限制称为同源策略。只有浏览器上才有同源政策。

举例来说,http://www.example.com/dir/page.html 这个网址,协议是http://,域名是www.example.com,端口是80(默认端口可以省略)。它的同源情况如下。

  1. http://www.example.com/dir2/other.html:同源
  2. https://www.example.com/dir/other.html:不同源(协议不同)
  3. http://.example.com/dir/other.html:不同源(域名不同)
  4. http://www.example.com:81/dir/other.html:不同源(端口不同)

同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据。

限制范围

  1. Cookie、LocalStorage 和 IndexDB 无法读取。
  2. DOM 无法获得。
  3. AJAX 请求不能发送。

下面我将说一下针对浏览器下不同源的AJAX 请求不能发送所采取的两种跨域措施(实际上是发送了的,但是由于同源保护,无法读取到数据)

CORS跨域请求

CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法。相比JSONP只能发GET请求,CORS允许任何类型的请求。但是只有在ie8以上支持。
它的基本**是:它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

1.简单模式 (GET、POST)
目标服务器在响应头里添加 Access-Control-Allow-Origin: http://xxx.com 即可,服务端仅允许来自 http://xxx.com 的访问

response.setHeader('Access-Control-Allow-Origin', 'http://frank.com')

2.复杂模式(除了GET、POST)
目标服务器在响应头里添加以下代码

response.setHeader('Access-Control-Allow-Origin', 'http://frank.com')
response.setHeader('Access-Control-Allow-Methods','POST,GET ,OPTIONS,PUT,PATCH,DELETE,HEAD')

会发两次请求,第一次是 OPTIONS 请求,询问目标服务器是否允许 PUT/PATCH等,如果允许,则发真正的请求。

JSONP跨域请求

JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持。
它的基本**是,网页通过添加一个 script 元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
1.让目标网站在一个 xxx.js 里放置数据,形式是 JSON + Padding

{{callback}}({
"name":"frank",
"qb":10000
})

2.本网站使用 script 加载 xxx.js

var script = document.createElement('script');
script.src = 'http://qq.com/xxx.js';
script.onload = function () {
       console.log('加载xxx.js成功')
      console.log(window.frankUser)
}
document.head.appendChild(script);

3.约定用 callback=xxx 来交流
将2的代码改成如下:

function xxx(data){
    console.log('我得到的数据是')
   console.log(data)
}
var script = document.createElement('script')
script.src = 'http://qq.com/xxx.js?callback=xxx'
document.head.appendChild(script)

在nodejs上修改代码如下:

if(path === '/xxx.js'){
var callback = query.callback
var string = fs.readFileSync('./xxx.js', 'utf8')
response.setHeader('Content-Type', 'text/javascript;charset=utf-8')
setTimeout(function(){
response.end(string.replace('{{callback}}', callback))
}, Math.random() * 1000)
}

4.将3的修改好的代码做封装

jsonp('http://qq.com/xxx.js',function(data){
    console.log('第一次')
    console.log(data)
})
jsonp('http://qq.com/xxx.js',function(data){
    console.log('第二次')
    console.log(data)
})
function jsonp(url,fn){
    var functionName='Frank'+parseInt(Math.random()*100000,10)
    window[functionName]=fn
    var script = document.createElement('script')
    script.src = url+'?callback='+functionName
    document.head.appendChild(script)
}
  1. jQuery 用法
$.ajax({
url:'http://qq.com/xxx.js',
dataType:'jsonp',
success:function(data){
console.log('第一次')
console.log(data)
}
})

JSONP 和CROS的区别

1.原理 上JSONP 是 script,CROS 是 JS 发出的请求
2.JSONP 只能 GET,CROS 都行
3.JSONP 不太安全,因为大家都可以访问(没有限制),CROS 有跨域限制

浏览器引擎科普

首先解释一下浏览器内核(引擎)是什么东西。英文叫做:Rendering Engine,中文翻译很多,排版引擎、解释引擎、渲染引擎,现在流行称为浏览器内核,Rendering Engine,顾名思义,就是用来渲染网页内容的,将网页的代码转换为最终你看得见的页面。因为是排版,所以肯定会排版错位等问题。为什么会排版错位呢?有的是由于网站本身编写不规范,有的是由于浏览器本身的渲染不标准。

简单总结

1、使用Trident内核的浏览器(Windows):IE、Maxthon遨游、腾讯TT、The World世界之窗等;
2、使用Gecko内核的浏览器(跨平台):Netcape6及以上版本、Mozilla Firefox、MozillaSuite/SeaMonkey;
3、使用Presto内核的浏览器(跨平台):Opera7及以上版本;
4、使用Webkit内核的浏览器(跨平台):Safari
5、使用Blink内核的浏览器(跨平台):Chrome
补充:Webkit由KHTML(Linux)发展而来。Blink内核是谷歌公司针对Webkit内核,做的修订和精简。去掉了几十万行的没用的复杂代码,让效率更高。然后针对未来的网页格式,做了进一步优化,和效率提升的处理。所以Blink内核可以看成是Webkit的精简高效强化版。

有关overflow:hidden的解释

overflow:hidden的意思

超出的部分要裁剪

overflow:hidden的作用

  • 清除浮动
    float 的元素不占普通流的位置,而普通流的包含块要根据内容高度裁剪隐藏。
    如果高度默认(auto)即不设高度,那么不计算其内浮动元素高度就裁剪,可能会裁剪掉float,这是反布局常识的。所以如果没有明确设定内容器高情况下,他要计算内容全部高度才能确定在什么位置hidden,浮动的高度就要被计算进去,顺带达成了清除浮动的目标。
  • 隐藏溢出
    当普通流的包含块高度设定时,他会根据包含块高度才hidden,当内容高度超过包含块是超出的部分就会被隐藏。
    #具体实例
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>JS Bin</title>
</head>
<body>
  <div id="box">
    <div id="content">
    </div>
  </div>
</body>
</html>
#box{
  border:1px solid black;
  width:50px; 
  background:#000; 
  height:50px;
  overflow: hidden;
 } 
# content { 
  border:1px solid yellow;
  float:left; 
  width:100px; 
  height:100px; 
  background:red;
 } 

当我们没有给box设置高度的时候,content 的高度,就会撑开box,这就是清除浮动。当我们给box加上一个高度值,那么无论content 的高度是多少,box这个高度都是我们设定的值。而当content 的高度超过box的高度的时候,超出的部分就会被隐藏。这就是隐藏溢出的含义!
注:引用了部分知乎貘吃馍香的回答。

JS诞生简述

1994年,网景公司(Netscape)发布了Navigator浏览器0.9版,但这个版本的浏览器只能用来浏览,不具备与访问者互动的能力。网景公司急需一种网页脚本语言,使得浏览器可以与网页互动。
Brendan Eich被指定为这种"简化版Java语言"的设计师。
总的来说,他的设计思路是这样的:
  (1)借鉴C语言的基本语法;
  (2)借鉴Java语言的数据类型和内存管理;
  (3)借鉴Scheme语言,将函数提升到"第一等公民"(first class)的地位;
  (4)借鉴Self语言,使用基于原型(prototype)的继承机制。
所以,Javascript语言实际上是两种语言风格的混合产物----(简化的)函数式编程+(简化的)面向对象编程。这是由Brendan Eich(函数式编程)与网景公司(面向对象编程)共同决定的。

浏览器事件机制

浏览器事件机制(即冒泡和捕获,也称为事件流)

基础知识

  1. 操作系统最先知道用户点击了鼠标,浏览器次之
  2. child 被点击了,意味着 parent 也被点击了
  3. 如果我同时监听了 child 和 parent,那么谁先通知我?这是个问题。

捕获阶段

早期 Navigator 支持
parent 先通知,child 后通知

冒泡阶段

IE支持
child 先通知,parent 后通知
(onclick 就是在冒泡阶段被通知)

W3C 事件模型

既支持捕获又支持冒泡(先捕获后冒泡)

举例说明事件机制(混用)

有两个div,一个parent,一个child,parent包含child.当用户点击child时先发生捕获阶段,通知parent你孩子被点击了是否需要处理一下后通知child你被点击了是否需要处理一下,之后发生冒泡阶段先通知child你被点击了是否需要处理后通知parent你孩子被点击了是否需要处理一下
注:若点击的是你自己,就没有什么捕获和冒泡,谁先监听就先触发谁。

原型链

什么是原型链

我们知道 JS 有对象,比如

var obj = { name: 'obj' }

我们可以对 obj 进行一些操作,包括

  • 「读」属性
  • 「新增」属性
  • 「更新」属性
  • 「删除」属性

下面我们主要来看一下「读」和「新增」属性。

为什么有 valueOf / toString 属性呢?

在我们没有对 obj 进行任何其他操作之前,发现 obj 已经有几个属性(方法)了:

那么问题来了:valueOf / toString / constructor 是怎么来?我们并没有给 obj.valueOf 赋值呀。
要搞清楚 valueOf / toString / constructor 是怎么来的,就要用到 console.dir 了。

上面这个图有点难懂,我手画一个示意图:
我们发现 console.dir(obj) 打出来的结果是:

  1. obj 本身有一个属性 name(这是我们给它加的)
  2. obj 还有一个属性叫做 __ proto __(它是一个对象)
  3. obj.__ proto __ 有很多属性,包括 valueOf、toString、constructor 等
  4. obj.__ proto __ 其实也有一个叫做 __ proto __ 的属性(console.log 没有显示),值为 null

现在回到我们的问题:obj 为什么会拥有 valueOf / toString / constructor 这几个属性?
答案:这跟 __ proto __ 有关。

当我们「读取」 obj.toString 时,JS 引擎会做下面的事情:

  1. 看看 obj 对象本身有没有 toString 属性。没有就走到下一步。
  2. 看看 obj.__ proto __ 对象有没有 toString 属性,发现 obj.__ proto __ 有 toString 属性,于是找到了
    所以 obj.toString 实际上就是第 2 步中找到的 obj.__ proto __.toString。
    可以想象,
  3. 如果 obj.__ proto __ 没有,那么浏览器会继续查看 obj.__ proto __. __ proto __
  4. 如果 obj.__ proto __ . __ proto __ 也没有,那么浏览器会继续查看 obj.__ proto __ . __ proto __ . __ proto __
  5. 直到找到 toString 或者 __ proto __ 为 null。

上面的过程,就是「读」属性的「搜索过程」。
而这个「搜索过程」,是连着由 proto 组成的链子一直走的。
这个链子,就叫做「原型链」。

原型链图:

共享原型链

现在我们有另一个对象

var obj2 = { name: 'obj2' }

如图:
那么 obj.toString 和 obj2.toString 其实是同一个东西,也就是 obj2.__ proto __.toString。
这有什么意义呢?
如果我们改写 obj2. __ proto __.toString,那么 obj.toString 其实也会变!
这样 obj 和 obj2 就是具有某些相同行为的对象,这就是意义所在。

差异化

如果我们想让 obj.toString 和 obj2.toString 的行为不同怎么做呢?直接赋值就好了:

obj.toString = function(){ return '新的 toString 方法' }

总结:
「读」属性时会沿着原型链搜索
「新增」属性时不会去看原型链(但是如果你给这个属性加了一些配置,则不一样)。

参考文章:https://zhuanlan.zhihu.com/p/23090041?refer=study-fe

this在具体项目中是什么

之前写的this是关于this的基本知识,但遇到具体情境(不能看到具体call情况)又需要根据具体情境讨论

具体情境下如何确定 this 的值

  1. 看源码中对应的函数是怎么被 call 的(这是最靠谱的办法)
  2. 看文档
  3. console.log(this)
  4. 不要瞎猜,你猜不到的

Event Handler 中的 this

btn.addEventListener('click' ,function handler(){
  console.log(this) // 请问这里的 this 是什么
})

我们说过 this 都是由 call 或 apply 指定的,那么你只需要找到 handler 被调用时的代码就行了。
可是我哪知道 addEventListener 的源代码呀
是呀,addEventListener 是浏览器内置的方法,我们看不见源代码。
所以,你只能看文档了
MDN 这样说

通常来说this的值是触发事件的元素的引用,这种特性在多个相似的元素使用同一个通用事件监听器时非常让人满意。 当使用 addEventListener() 为一个元素注册事件的时候,句柄里的 this 值是该元素的引用。其与传递给句柄的 event 参数的 currentTarget 属性的值一样。

由于浏览器知道你不方便看源码里是怎么 call handler 的,所以直接在文档里告诉你了,你可以假想浏览器的源码是这样写的:

// 当事件被触发时
handler.call(event.currentTarget, event)
// 那么 this 是什么不言而喻

#jQuery Event Handler 中的 this
那么下面代码中的 this 是什么呢:

$ul.on('click', 'li' , function(){ console.log(this)})

同样,不要瞎猜,你要么看 jQuery 源码是怎么 call 这个函数的,要么看jQuery 文档:

当jQuery的调用处理程序时,this关键字指向的是当前正在执行事件的元素。对于直接事件而言,this 代表绑定事件的元素。对于代理事件而言,this 则代表了与 selector相匹配的元素。(注意,如果事件是从后代元素冒泡上来的话,那么 this 就有可能不等于 event.target。)若要使用 jQuery 的相关方法,可以根据当前元素创建一个 jQuery 对象,即使用 $(this)。
#如何强制指定 this 的值?

自己写 call / apply 即可:

function handlerWrapper(event){
  function handler(){
    console.log(this) // 请问这里的 this 是什么
  }

  handler.call({name:'饥人谷'}, event)
}
btn.addEventListener('click', handlerWrapper)

你也可以直接使用 bind,与上面的代码效果差不多:

function handler(){
  console.log(this) // 请问这里的 this 是什么
}
var handlerWrapper = handler.bind({name:'饥人谷'})
btn.addEventListener('click', handlerWrapper)

上面三句代码可以挤成一句:

btn.addEventListener('click', function(){
  console.log(this) // 请问这里的 this 是什么
}.bind({name:'饥人谷'}))

这是前端里一个常见的套路。
答案都是:{name:'饥人谷'}

HTML 中常用的 meta 元素

1.meta的意义:

在HTML文档中,meta元素可放置在head标签内用于定义整个文档层面的元数据信息。使用meta标签时无需将标签闭合。

2.meta的使用:

除了通用的全局属性,meta元素还可以拥有4个特有属性:name、http-equiv、charset和content。
meta元素可以用name属性表示文档级元数据,以http-equiv属性表示编程指示,以及charset属性用来表示HTML文档序列化为字符串而成的文件的字符编码声明。
对于name、http-equiv和charset,任何meta元素必须拥有且只能拥有其中的一个,这一属性及其值决定了该meta元素所表达的作用。如果meta元素拥有name属性或者http-equiv属性,则该meta元素必须同时具备content属性用于描述具体的元数据信息(如果content属性缺失,则其值默认为空字符串);如果meta元素拥有charset属性,则content属性不应出现。
注:一个HTML文档中拥有charset属性的meta元素最多只能出现一个。这很好理解 -- 整个文档层面的编码信息只需要出现一次即可。

三个可选属性:

属性 描述
http-equiv content-language, content-type, expires, refresh,set-cookie 把 content 属性关联到 HTTP 头部。
name application-name, author, description, keywords, generator, revised, others 把 content 属性关联到一个名称。
charset utf-8... 设定自身的编码

必选属性:

属性 描述
content some_text 定义与 http-equiv 或 name 属性相关的元信息

3.具体属性

1.name

对于meta元素的name属性,HTML5文档定义了一些标准值:

(application-name) 如果HTML页面是一个Web应用,则可以用name值为application-name的meta元素来定义该Web应用的名称。在使用application-name时,可通过同时定义meta元素的lang值来设定不同自然语言情况下该Web应用的名称,从而实现Web应用名称的本地化。不过在同一个HTML文档中,不允许出现两个application-name其所属的meta元素lang值相同的情况 -- 同一种语言的情况下,Web应用的名称只能有一个。对于通过application-name所定义的Web应用的名称,浏览器可以将其作为窗口顶部的名称信息加以展示(也即,其优先级高于head标签中的title元素)。
(author)name值为author的meta元素可用于定义当前文档的作者信息。
(description)name值为description的meta元素可用于定义当前文档的具体描述信息,这种meta元素在同一个HTML文档中最多只能出现一个。在Web的早期历史中,搜索引擎会根据这个description信息来处理HTML文档;但由于之后SEO对此属性的滥用,导致如今搜索引擎对此meta信息的参考权重已经大为降低。
(generator)对于由Dreamweaver等网页制作软件所制作的HTML文档,name值为generator的meta元素可用于记录该网页制作软件的信息。
(keywords)name值为keywords的meta元素可接受以逗号分隔的多个关键词作为content,用于描述当前文档的关键词信息。与description一样,由于SEO滥用,如今的搜索引擎在处理HTML文档的时候已经不考虑keywords信息了。

2.http-equiv

http-equiv属性接受有限的几个可选值,用于从浏览器角度描述当前文档的元数据信息 -- 其出发点及实质是模拟HTTP Response头中的相应字段。这些可选值包括:

(content-language)meta标签可以使用http-equiv="content-language"来定义当前文档的自然语言。不过HTML5标准并不建议这么做,对于文档自然语言的定义,标准建议使用lang属性。
(content-type)meta标签可以通过使用http-equiv="content-type"来定义当前文档的MIME Type及编码,其实质是模拟HTTP Response中的content-type头。一般情况下,这一meta标签会写成下面这个样子:。由于作用相同,http-equiv值为content-type的meta标签与拥有charset属性的meta标签在同一个HTML文档中不能同时出现。
(refresh)在meta标签中使用http-equiv="refresh"可实现定时跳转,此时可用meta标签的content值来表示跳转前的等待时间以及页面跳转的目的地。但由于用户体验的原因,http-equiv="refresh"的实际应用已经很少了。以下是两个简单的例子:

(set-cookie)在meta标签中使用http-equiv="set-cookie"可实现浏览器cookie写入,不过HTML5标准并不建议这么做 -- 正确的做法应当是在真正的HTTP Response头中来实现set-cookie行为。

3.charset

HTML文档可以通过拥有charset属性的meta标签来设定自身的编码。无论是通过这种方式,还是通过http-equiv="content-type"的方式,文档的编码信息必须得到定义。不过当HTML文档作为包含在iframe中的子文档而存在的情况下,标准规定不能对该文档进行编码定义(此时其编码取决于包含它的那个外部文档)。
注:HTML5标准规定文档的作者(Web开发人员)应当使用UTF-8作为HTML文档的编码。

Promise

什么是promise

Promises对象是CommonJS工作组提出的一种规范,目的是为异步编程提供统一接口。
简单说,它的**是,每一个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数。
window.Promise是 JS 的一个全局对象。

Promise 规格文档

目前的 Promise 都遵循 Promises/A+ 规范。
看完规范和Promise mdn你可以了解 Promise 的全貌

Promise 的用途。

Promise 之前的时代——回调时代

假设我们调用ajax函数获取数据,它成功和失败时各调用一个函数(回调):

  ajax({
    method: 'GET',
    url: '/x',
    success: successFn
    error:  errorFn
  })

function successFn(responseText){
      document.querySelector('#y').innerText = responseText
    }

function errorFn(status){
  alert('请求失败,状态码为' + status)
}

但是我们调用的时候可能会忘记参数名(success/error,success/fail,win/lose?),为解决这个问题出现了Promise。

Promise

Promise 的思路就是 ajax 返回一个对象,你往这个对象上挂回调:

var promise = ajax({method: 'GET',url: '/x'})
promise.then(successFn, errorFn)

当用户信息加载完毕,成功就执行successFn ,失败执行errorFn
把上面两句话合并成一句就是这样的:

ajax({method: 'GET',url: '/x'}).then(successFn, errorFn)

如果你想在用户信息获取结束后做更多事,可以继续 .then:

ajax({method:'GET',url:'/x'}).then(s1,e1).then(s2,e2)

请求成功后,会依次执行 s1、s2 。

promise可以使回调变得可控。你对比下面两个写法就知道了。

ajax(method: 'GET',url: '/x',successFn, errorFn)

ajax(method: 'GET',url: '/x',).then(successFn, errorFn)

用 Promise 之前,你不能确定successFn 是第几个参数;
用 Promise 之后,所有的回调都是
.then(success, error)
这样的形式。

总结Promise 的好处

  1. 不用再去想参数名了(success/error,success/fail,win/lose)
  2. then的形式
    promise.then(s1,e1).then(s2,e2)
    promise.then(s1,e1); promise.then(s2,e2)
    两者的区别就是前者第一次then之后的promise可能不是原来的promise
  3. Promise API
    Promise.all([promise1, promise2]).then...
    //promise1, promise2执行完之后再then
    Promise.race([promise1, promise2]).then...
    //promise1, promise2有一个执行完之后就then
  4. Promise 一定是异步的,不可能同步
    //then的存在造成了Promise 一定是异步的

ajax函数代码

为方便理解我之前没给出ajax函数代码,现在给出ajax函数代码

回调时代

function ajax(options){
  let {method, url, success, error} = options
  if(!method){ throw new Error('你神经病,怎么不传 method') } 
  url = url || location.href
  let xhr = new XMLHttpRequest()
  xhr.open(method, url)
  xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
      if(xhr.status>=200 && xhr.status < 400){
        success && success.call(null, xhr.responseText, xhr)
      }else if(xhr.status >= 400){
        error && error.call(null, xhr.status, xhr)
      }
    }
  }
  xhr.send()
}

返回promise对象

function ajax(options){
  return new Promise(function(resolve, reject){ // 1
    let {method, url} = options
    if(!method){ throw new Error('你神经病,怎么不传 method') } 
    url = url || location.href
    let xhr = new XMLHttpRequest()
    xhr.open(method, url)
    xhr.onreadystatechange = function(){
      if(xhr.readyState === 4){
        if(xhr.status>=200 && xhr.status < 400){
          resolve.call(null, xhr.responseText) // 2
        }else if(xhr.status >= 400){
          reject.call(null, xhr) // 3
        }
      }
    }
    xhr.send()
  })
}

这一代人的学习(如何学习前端)

问题

  • 焦虑
    选择多,新知识更新快
  • 过去的学习方式(解决焦虑)要改变
    读书,看报,上学不适合如今前端学习
  • 时间碎片化
    没有整块时间
  • 没有学成归来,系统性学习这一说
    终生学习,跨界学习
    注:1.现代的成功:要有两个领域前20%(如编程,乐器,讨巧做法---演讲)2.学习要不求甚解(融合者)

建议

  1. 跟人学(阮一峰)
  2. 学概念(如:HTML ,CSS,JS,管理上司)
  3. 过一道(表达一次,如博客,演讲)
  4. 碎片化-----系统性学习不适合:更新太快,成本太高
  • 时间零碎 三上
  • 知识点零碎 系统性学习不适合,定目标学习(见5)
  1. 目标(目标,方法,行动(自己搞定))
  • 定大目标----找工作
  • 小目标-------如:jQuery/DOM-----搜,问,抄-----总结

年长程序员的忠告

转载:
给程序员小弟弟小妹妹们的一些总结性忠告

展望未来,总结过去10年的程序员生涯,给程序员小弟弟小妹妹们的一些总结性忠告走过的路,回忆起来是那么曲折,把自己的一些心得体会分享给程序员兄弟姐妹们,虽然时代在变化,但是很可能你也会走我已经做过的10年的路程,有些心得体会你可以借鉴一下,觉得说得有道理的你就接纳,觉得说得没道理的,你就抛弃,以下是我发自内心的,给大家的忠告,特别是针对那些小弟弟妹妹们。

###1. 自己的户口档案、养老保险、医疗保险、住房公积金一定要保管好。
由于程序员行业每年跳槽一次,我不隐瞒大家,我至少换过5个以上的单位,这期间跳来跳去,甚至是城市都换过3个。还好户口没丢掉,其他都已经是乱了,好几个城市里,都有交过三金,甚至是一个程序的2个区里交的都有,那些东西,10年后,会变得很重要。你买房子若有公积金,可以取出来,贷款利率也会比较低一些,有孩子了,还需要上学,生病了还需要医疗保险。 特别是买房子时,你要商业贷款与公积金贷款的利率差别还是很大,有可能会有10万的差距。你平时都注意这些,会给你带来的损失会最小,例如每个月缴纳300元的公积金,公司也缴纳300元,你一个月能存下来600元,一年就是7200元,10年就是72000元。我以前都忽视了这些,到我需要买房子时,公积金里可能只有几千元,10年很快就过去了,结果我没能存下来多少公积金,医疗保险,养老金等更别提了,都已经稀里糊涂了,这些损失10年累加起来,是很庞大的数字,大家要注意,跳槽换工作时也要保护好自身的利益,现在房价很贵,你可能是跟我一样,大山里出来打拼的娃子,家里也没有丰厚的积蓄,只有靠自己拼搏,买房子是人生的一件大事,等你到了10年,才想到这个事情,已经晚了,特别是孩子要上学,上幼儿园等,需要户口啥的都要齐全。
###2. 不要轻易换笔记本电脑,不要跟潮流,不要买过多的电子产品,不要过于频繁的更换手机。
这方面我的经验教训也是惨痛的。我大概前后购买过5-6个笔记本,以前的都是1万多元一台,最近买的是一台是1万多给女朋友的,自己买了一台是7500元左右,手机大概换过接近10个了,这些钱加起来也足够有10万以上了,你可能一不小心就购买了这些电子产品,但是时间长了,你一回过头来想想,你为什么赚得也不少,但是为什么还是那么穷,是因为你购买这些电子产品花费了过多的金钱了,平时笔记本啥的贵重物品要保护好,我一个同事不小心丢了2台笔记本电脑,接近2万的损失啊,你净赚2万,不是那么容易的,这个窟窿不是开玩笑的,我曾经也被人偷了一个崭新的笔记本,损失1.5万左右,更糟糕的是最新的代码也丢被偷了。
###3. 这年代外语、学历、职称、驾驶证还是蛮重要的。
想找高薪,外资企业是正确的选择,在同样的打工里,外资企业的收入普遍是高的,我就想不明白,我们的赚钱能力怎么就比不过人家了,社会不断发展,将来可能去外国就像串门一样了,也说不定的,外语好将来的就业机会也会更多更广一些。 学历并不代表啥,但是学历也是敲门砖,例如有300个应聘者,那至少重点本科以下的,统统不看了,因为实在是来不及看了,你再厉害也被挡在机会的门外了,同样有时候你想改行什么的,职称也很重要,最起码评个中级职称,说不定还有机会能进入大学或者政府部门还是有可能性。 若有充裕的时间,应该把驾驶证考了,因为你越到后面越忙与工作家庭,没机会学车了也说不定的,平时也别光顾拼命工作,工作10年后你才发现,原来身边的人都至少硕士学历了,你被社会自动淘汰了,我现在就有这个感觉,虽然我带过很多硕士,他们的就业机会比我还好,经常能进入名牌企业,我也一直进不去。
###4. 不要谈过多的女朋友,谈女朋友要看准,下手要稳准狠。
我谈过2个女朋友,平均每个女朋友身上的开支前后大概会有10万左右,还好我不用谈第3个女朋友了,若投资失误,那也是很残忍的,谈女朋友也会消耗很多时间精力、还会消耗很多金钱,实话的讲的确是这样的,人家女孩子也值钱啊,凭什么就那么轻易的跟你啊,我跟第一个朋友分手时,我的生活至少是倒退了3-4年,一切从零开始,一切从头开始,我劝大家谈女朋友是人生最大的一笔买卖,投资失误会有惨痛的后果,不仅仅是金钱上的损失,更会有精神、心灵上的沉重打击,大家要学会珍惜女朋友,要学会哄好女朋友,让老婆开心每一天,虽然鱼儿上钩了,不用再下鱼饵了,偶尔也别忘记放点米,这个鱼要是脱钩了,那不是开玩笑的。
###5. 工作不要更换得太过于频繁,选好了行业方向最好别更换太频繁。
换工作,换行业方向,就像熊掰苞米一样的道理,有时候是丢了芝麻捡西瓜,有时候是丢了西瓜捡芝麻,这个道理我就不多讲了,大家都应该能明白的。
###6. 要对身边的人好,要得到老板的信任、同事的认可及支持、珍惜良好的工作环境。
有个朋友的QQ名字很有意思,“只爱陌生人”,陌生人是很有意思,但是最关键时刻,还是需要靠非陌生人,你每天跟同事一起生活,要维系好身边的人。你的成功与失败,往往是你身边的30-40个人决定的。你就是世界首富,他身边也是那么不超过100个人的在左右着他的生活,当你工作10年了,没一个老板信任你,没几个要好的同事朋友,那你惨了,你在这个世界上已经是很孤单了,你的收入,其实大多是来自这些身边的朋友给你介绍的生意,不大会网上掉几个馅饼的。 现在你身边的人有可能在不久的将来,给你提供很多好机会。
###7. 钱很重要,但是生活质量比钱还重要,工作是很重要,但是家人比工作还重要。
钱不是万能的,但是没钱是万万不能的。钱赚了,身体夸了,全送给医院了,钱赚了,身心疲惫了,人活着为了啥?不就为了开开心心生活嘛?工作重要,但是失去了家人的爱,失去了女朋友,失去了老婆孩子,那这个工作有啥用了?工作很容易就换了,家人是换不了的,老婆不是想换就换的,孩子不是想换就换的,连自己的家庭都不负责的人,怎么可能对公司负责呢?我一直是这个观念,来面试时觉得工作更重要的,我们一般不录取的,那太假了,或者太不懂事了。
###8. 工作累了,也别太贪玩,有时候还是需要多想想如何才能赚钱。
时间一晃就过去了,工作累了是可以适当放松,但是别太贪玩,10年很容易就过去了,10年后你要买房子,要娶老婆,要买车子,要生娃娃,身体也会变得脆弱一些,需要良好的生活习惯,也经不起通宵了,通宵一次,你要低迷好几天才能缓过劲儿来,跟20刚出头完全不一样了,用钱的地方多了去了,父母也会变得更老一些,可能也需要你的照顾,整个家子都指望你赚钱,别到了这个时候,你才意识到赚钱是那么的重要,更何况现在城市的房价,动不动就是100万,加上按揭的利息,你很可能需要支付150万。还可能需要装修,买车子。可能你身上的压力是200万。别觉得谈钱就俗,你要学会赚钱,要有个需要赚钱的良好意识,当然你出身富裕家庭,就不用考虑这些因素了。
###9. 每天一点点进步,每月一点点积累,要敬业要爱业,我们给别人提供的也是服务。
总有一天,你也会有累的时候,你也会有老的时候,这时候,你要靠啥呢?就要靠你平时的积累,你10年的积累,可以打倒很多竞争对手,他们再厉害,再怎么样,也很难抵得过你10年的积累,特别是后面5-10年的积累,成果会很明显,前面的1-5年,算是做软件的入门吧,除非你有高人指点,那可能2-3年就可以修成正果,软件在将来还是会值钱的,以为生活会越来越智能化,越来越数字化,软件的需求还是很有前途,最起码未来的10-20年里不用太担心失业问题了。
###10. 对程序员来讲,开发**、架构、代码就是财富,别老丢弃你的劳动成果,要学会保护你的劳动成果。
我大概7-8年前的代码都在手上,经常改进来改进去,维护来维护去,在一定的程度上,让我生活轻松了不少,因为我不用什么都从头来过,我只要痛苦一次,以后就要反复重复利用,软件的价值在于重复利用,而不是每个东西,都从头开发,那永远也是辛苦的程序员,这个生活质量就别提了,不管自己的代码丑还是拿不出手,要学会精心维护,每天改进一点点,每个月一个小进步,每年一个大进步,多年的积累是宝贵的,这个早晚也会给你带来丰厚的收益。
###11. 当程序员要防止原地踏步,不是工作年限长了,经验就丰富了,能力就强了,年纪越大工作越难找。
我有一个朋友跟我开玩笑,工作5年的人,可能能力差距会很大,为什么呢?因为第一年他们干的事情都是一样的,都写程序了,2个人可能由于价值观不一样,5年后差距会很大,甚至是大到无法追赶的程度,为啥?因为还有机会的因素在里面,有的人干了5年,还是在原地踏步,天天只会写那些添加、删除、修改的代码。那你得注意了,需要不断的提高自己,才是硬道理。例如你会SQLServer,那要试着学习Oracle, 你是做C/S的,那得需要提高到B/S的,你是做单机软件的,那得需要提高到网络软件,你只关注自己的工作的,需要学会管理,关心他人的工作。你是当程序员的,要试着提高当项目经理、部门经理,公司的总监等等,人有野心有目标才会不断进步,最俗的为了多赚钱,提高工作职位工作岗位,工作单位,也是可以理解的。 年纪越大工作越难找,例如3-4千的工作是随便找找,玩一样,但是你30过后,最起码要找月薪上1万的工作,这样的工作是机会也少,一般小公司也给不起,还得找个好公司才可以,好公司又不是天天招聘人,天天缺好的工作岗位,说不好听点儿,小公司的老板才赚多少啊?他来钱也很不容易的,小池塘就不好容得下大鲨鱼了。
###12. 当创业的收入比打工还少时,那就别创业,要找比自己能力强的人创业,你不会吃亏。
创业的收入,比打工还少,那就是瞎扯蛋,恶搞。创业的真正意思并不是要你去吃苦没钱赚,那是忽悠无知的人的。当你创业时的收入,比打工还多,那你可以考虑创业,没有工资什么的,股份啥的,都是瞎扯蛋。 不要跟自己能力还弱的人一起创业,那损失最大的,很可能就是你,要创业,也要找比自己强的人一起创业,最起码赚不到钱,还能学到不少。不会有过多的损失。别热血一沸腾就创业了,创业了,也别烧自己的钱,家人的钱,那是很不抗烧的,没几下几十万就烧干了。其实打工,也是创业的开始,每个月都能拿到钱,还可以学到知识,什么公司的股份都是空话,没几个小公司能成功,开起来了也走不了3年就分家了,都忽悠小孩子玩的,除非真的有科技含量或者是客户资源的,否则股份是一文钱不值的,就算创业每个月也按时拿工资才是硬道理。
###13. 未来的生活节奏会更快,生活压力会更大,竞争会更激烈,社会服务体系会更完善。
在未来,我们享受良好的服务的同时,也会为别人提供更良好的服务,需要在技能上还是服务质量上的要求会更高更严格。平时要注意提高自己,不要被时代淘汰掉,我从小的朋友,一波又一波被社会无情的淘汰了,很小的时候,我出生在大草原与大山的交界处,我小时候的玩伴,还在大山里,我跟着家人杀出来了,我小学、中学、大学、工作上的、这10年,我一直很坚强的拼搏下来,很不容易的在杭州立住脚了,说实话,参加工作后的十年,也是不断拼搏,不断提高的十年。

var let变量提升引发的思考

准备知识

首先我们知道js中有两种作用域,一是全局作用域,二是函数作用域,然而在es6引入了let之后就有了块级作用域。也就是说现在有三种作用域了。知道了作用域我们就可以来聊一下变量提升了,一般来说变量提升都是提升到变量作用域第一行。

var的变量提升

var a=1         //var 全局作用域变量
function foo(){
  alert(a) //a是什么?
  var a=2       //var 函数作用域变量
}
foo.call()

做这种题一般先进行转换(变量提升):先找声明,再看代码。

提升结果如下:

找声明:var a
       function foo(){
         //函数里代码找声明时不看,调用时再看
         var a
         alert(a)
         a=2
       }
看代码:a=1
       foo.call()//调用了,看函数代码

由上面可以看到a为undefined
##let的变量提升
let 有变量提升?答案是有的,听我慢慢说。

let x = 'global'
{
  console.log(x) // Uncaught ReferenceError: x is not defined
  let x = 1
}

你能解释一下为什么x会报错。
能想通吗?
我们先从提升这两个字入手理解一下

提升

首先明确一点:提升不是一个技术名词。
要搞清楚提升的本质,需要理解 JS 变量的「创建create、初始化initialize 和赋值assign」
有的地方把创建说成是声明(declare),为了将这个概念与变量声明区别开,我故意不使用声明这个字眼。
有的地方把初始化叫做绑定(binding),但我感觉这个词不如初始化形象。

var 声明的「创建、初始化和赋值」过程

function fn(){ 
  var x = 1 
  var y = 2
}
fn()

在执行 fn 时,会有以下过程(不完全):

  1. 进入 fn,为 fn 创建一个环境。
  2. 找到 fn 中所有用 var 声明的变量,在这个环境中「创建」这些变量(即 x 和 y)。
  3. 将这些变量「初始化」为 undefined。
  4. 开始执行代码
    x = 1 将 x 变量「赋值」为 1
    y = 2 将 y 变量「赋值」为 2

也就是说 var 声明会在代码执行之前就将「创建变量,并将其初始化为 undefined」。
这就解释了为什么在 var x = 1 之前 console.log(x) 会得到 undefined。

function 声明的「创建、初始化和赋值」过程

fn2()
function fn2(){ 
  console.log(2)
}

JS 引擎会有一下过程:
1.找到所有用 function 声明的变量,在环境中「创建」这些变量。
2.将这些变量「初始化」并「赋值」为 function(){ console.log(2) }。
3.开始执行代码 fn2()

也就是说 function 声明会在代码执行之前就「创建、初始化并赋值」。

let 声明的「创建、初始化和赋值」过程

{
 let x = 1 
 x = 2
}

我们只看 {} 里面的过程:
1.找到所有用 let 声明的变量,在环境中「创建」这些变量
2.开始执行代码(注意现在还没有初始化)
3.执行 x = 1,将 x 「初始化」为 1(这并不是一次赋值,如果代码是 let x,就将 x 初始化为 undefined)
3.执行 x = 2,对 x 进行「赋值」

这就解释了为什么在 之前let x 之前使用 x 会报错:

let x = 'global'{ 
  console.log(x) // Uncaught ReferenceError: x is not defined 
  let x = 1
}

原因有两个

  1. console.log(x) 中的 x 指的是下面的 x,而不是全局的 x
  2. 执行 log 时 x 还没「初始化」,所以不能使用(也就是所谓的暂时死区)

总的来说:

  1. let 的「创建」过程被提升了,但是初始化没有提升。
  2. var 的「创建」和「初始化」都被提升了。
  3. function 的「创建」「初始化」和「赋值」都被提升了。
    也就是提升的东西一步步变多了。

讲了这么多我们顺便来总结一下let的特点

let的5个特点

  1. let 块级作用域变量

  2. let无法重复声明

  3. let和for循环配合会有神奇现象

    var liList = document.querySelectorAll('li') // 共5个li
    for( let i=0; i<liList.length; i++){
      liList[i].onclick = function(){
        console.log(i)///为何分别打印出 0、1、2、3、4,把let 改成var 就是打印出5个4?
      }
    }
    

    原因

    1. for( let i = 0; i< 5; i++) 这句话的圆括号之间,有一个隐藏的作用域
    2. for( let i = 0; i< 5; i++) { 循环体 } 在每次执行循环体之前,JS 引擎会把 i 在循环体的
      上下文中重新声明及初始化一次。

    上面代码等价于

    var liList = document.querySelectorAll('li') // 共5个li
    for( let i=0; i<liList.length; i++){
      let i = 隐藏作用域中的i // 看这里看这里看这里
      liList[i].onclick = function(){
        console.log(i)
      }
    }
    

    这时:let i 保留的隐藏作用域中的 i 的值,所以在后者变化的时候,前者并不会变化。
    而console.log 的是前者,所以不会出现分别打印出 0、1、2、3、4

  4. let 会提升,提升到block(块级作用域)第一行

  5. 但是有TDZ(临时死亡区域),let声明之前区域不能使用。

参考文章:https://zhuanlan.zhihu.com/p/28140450?utm_medium=social&utm_source=qq

flex布局

flex之前

我们用什么布局
主要使用(5种):

  • normal flow
  • float+flow
  • position relative+absolute
  • dispaly inline-block
  • 负margin

基本概念

50_WQ_AE{{1V05WP1KV1UO9.png
主轴main axis主尺寸main size主轴起点main start主轴终点main end
侧轴cross axis侧尺寸cross size侧轴起点cross start侧轴终点cross end

flex来了

一种新的布局方式——Flex布局

  1. 块级布局侧重垂直方向,行内布局侧重水平方向,flex布局是与方向无关
  2. flex布局可以实现空间自动分配自动对齐(flexible:弹性,灵活)
  3. flex适用于简单的线性布局,更复杂的布局要交给grid布局(还没发布)

flex container的属性

  • flex-direction方向
    flex-direction:low/column/low-reverse/column-reverse
  • flex-wrap换行
    flex-wrap:warp/nowarp
  • flex-flow上面两个的简写
  • jusitify-content主轴方向对齐方式
    jusitify-content:space-between/space-around/flex-start/flex-end/center
  • align-items侧轴对齐方式
    align-items:strech/baseline/flex-start/flex-end/center
  • align-content多行列内容对齐方式
    align-content:strech/space-between/space-around/flex-start/flex-end/center

flex item的属性

  • flex-grow增长比例(空间过多时)
    flex-grow:1
  • flex-shrink收缩比例(空间不够时)
    flex-shrink:1
  • flex-basis默认大小(一般不用)
    flex-basis:100px
  • flex上面三个的缩写
    order顺序(代替双飞翼)
    order:1
  • align-self自身对齐方式
    align-self:center

理解闭包、立即执行函数、异步和回调

闭包

什么是闭包

一个函数使用了它外面的变量,这种用法就是闭包。闭包是一个马后炮的总结。

function xxx(){
    var lives = 30
    var bug = 'salkdjaslkdjaslkjd...100MB'   // IE bug
    function die(){
      lives -= 1
      return lives
    }
    return die
}

var dieFn = xxx()
// here
var currentLives = dieFn()

那为何要这样做呢(搞得这么麻烦):

闭包的作用

闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」。
因为如果是全局变量,容易被改,如果是局部变量,别人又访问不到。

上面这样用闭包,就可以用dieFn()来修改lives。

闭包造成内存泄露?

内存泄露是指你用不到(访问不到)的变量,依然占居着内存空间,不能被再次利用起来。

闭包里面的变量明明就是我们需要的变量(lives),所以不是内存泄露

为何有人说是?
因为 IE。IE 有 bug,IE 在我们使用完闭包之后,依然回收不了闭包里面引用的变量。

立即执行函数

什么是立即执行函数

声明一个匿名函数,立即执行它,就是立即执行函数

!function (){
    var lives = 30
    console.log(lives)
}.call()

感叹号可以换成 + - ~ 等符号,也可以换成括号。

那为什么要有这么个东西(好麻烦)

立即执行函数的作用

只有一个作用:创建一个独立的作用域。
这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
这个作用不就恰恰是闭包所需要的吗!!!
所以之前的函数可以写成

!function xxx(){
    var lives = 30
    var bug = 'salkdjaslkdjaslkjd...100MB'   // IE bug
    function die(){
      lives -= 1
      return lives
    }
    return die
}.call()

举例:

var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
  liList[i].onclick = function(){
    alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5
  }
}

因为在点击之前i早变成了6,每个监听的元素都为6。
那么怎么解决这个问题呢?用立即执行函数给每个 li 创造一个独立作用域即可

var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
  !function(ii){
    liList[ii].onclick = function(){
      alert(ii) // 0、1、2、3、4、5
    }
  }(i)
}

在立即执行函数执行的时候,i 的值被赋值给 ii,此后 ii 的值一直不变。

i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 ii 「分别」是 0、1、2、3、4、5。

异步+回调

什么是异步

同步:一定要等任务执行完了,得到结果,才执行下一个任务。

function taskSync = function(){
  return '同步任务的返回值'
}

var result = taskSync() // 那么 result 就是同步任务的结果
otherTask()             // 然后执行下一个任务

异步:不等任务执行完,直接执行下一个任务。相当于给前一个任务加个警报器,任务好了再告诉你去执行。

function taskAsync = function(){
  var result = setTimeout(function(){
    console.log('异步任务的结果')
  }, 3000)
  return result
}

var result = taskAsync() // result 不是异步任务的结果,而是一个 timer id。不懂?因为现在我是无法得到3秒后的result,只会得到他的定时器。
otherTask()              // 立即执行其他任务,不等异步任务结束

什么情况下需要用到异步?

如果几个任务互相独立,其中一个执行时间较长,那么一般就用异步地方式做这件事。

什么是回调

callback 就是(传给另一个函数调用的)函数。把括号里面的内容去掉,简化成:callback 就是一种函数。
具体来讲:
当一个函数 A 被作为参数传给另一个函数时 B,那么这个函数 A 就叫做回调(名词)。B 中调用 A 函数的过程,也叫做回调(动词)。
那回调有什么用呢?

回调的作用

回调通常用在获取「异步任务」的结果
之前异步的代码也可写成如下(为理解起见我简化了)

function async(fn){
   setTimeout(function(){
    fn('异步任务的结果')
  }, 3000)
  return 
}//函数声明

async(function  (xxx){
    console.log(xxx)
}) // 函数调用。3秒后执行fn,xxx 是异步任务的结果
otherTask()             

过程简单来说就是我调了async函数,然后在async函数里它调了fn函数(此时fn相当于是我传的参数function),调用的时候把'异步任务的结果'(此时'异步任务的结果'相当于xxx)传了出来。
其中function (xxx){ console.log(xxx)}和fn('异步任务的结果')都是回调,一个是名词,一个是动词。

远程登录

远程登录

远程登录另一台机器

SSH 原理与运用

  1. 用密码登录
    ssh user@host 密码:user
    (如ssh [email protected] 密码:student246r)

  2. 用 ssh key 登录
    2.1 首先你要准备两个key
    ssh-keygen -t rsa -b 4096 -C "[email protected]"
    (如ssh-keygen -t rsa -b 4096 -C "[email protected]")
    一个公钥(public key)
    一个私钥(private key)
    id_rsa 文件是私有密钥,id_rsa.pub 是公开密钥。
    2.2 把 public key 给远程机器(public key 可以随便给多个 host)
    ssh-copy-id user@host
    (如ssh-copy-id [email protected]
    2.3 之后就可以不用密码就可登录了
    ssh user@host
    (如ssh [email protected]

退出一台机器

  1. exit
  2. logout
  3. ctrl + D

Git命令行的使用

什么是git

Git是目前世界上最先进的分布式版本控制系统(没有之一),用于敏捷高效地处理任何或小或大的项目

远程仓库

创建公开密钥认证所需的ssh key

$ ssh-keygen -t rsa -b 4096 -c "[email protected]"
Generating public/private rsa key pair.
Enter file in which to save the key
(/Users/your_user_directory/.ssh/id_rsa): 按回车键
Enter passphrase (empty for no passphrase): 输入密码
Enter same passphrase again: 再次输入密码

id_rsa 文件是私有密钥,id_rsa.pub 是公开密钥。

添加公开密钥

登录github,点击右上角头像,选择Settings,再点击SSH and GPG keys,设置SSH keys。点击New SSH key 把id_rsa.pub 文件里的内容添加进去。完成以上设置后,就可以用手中的私人密钥GitHub 进行认证和通信了。

$ ssh -T [email protected]
The authenticity of host 'github.com (207.97.227.239)' can't be established.
RSA key fingerprint is fingerprint值 .
Are you sure you want to continue connecting (yes/no)? 输入yes
Hi hirocastest! You've successfully authenticated, but GitHub does not
provide shell access.

配置

git config --global user.name xxx #方便产品经理找(怼)你
git config --global user.email yyy #方便产品经理找(怼)你
git config --global push.default simple 
git config --global core.quotepath false #防止文件名变成数字
git config --global core.editor "vim" #使用vim编辑提交信息

这些配置都是在写 ~/.gitconfig 文件而已(--globa是指全局设置,应用于所以项目)

代码演示

mkdir git-demo
cd git-demo
git init
touch 1.txt # 编辑第一行文本
git status -sb
git add .
git status -sb
git commit -v
git remote add origin git@xxxxxxxx # 将当前仓库与远程仓库建立联系
git push -u origin master # -u 的意思是将本地分支与远程分支建立联系

基本操作

git init
创建 .git 目录(本地仓库)

git add
将 多行文字 纳入 git 控制范围(stage、历史的舞台)

git commit
存入 .git 目录

git log
展示历史

git show xxx(编号)
具体展现一个历史

git reset --hard xxx(编号)
回退到某个历史

git remote add xxx yyy
添加一个远程仓库,名字为 xxx,地址为 yyy

如果你要修改 yyy,可以使用 git remote set-url xxx zzz

git push
将 .git 上传到另一个目录

git clone
git clone 的作用

  1. 新建目录 xxx
  2. 解压远程 .git 目录到 xxx/.git

注:git clone 会帮你新建目录的!所以你别自己建目录!

git pull
更新本地仓库(.git)和本地文件

原则

git push 之前必须 git pull
git pull 之前必须 git commit
git commit 之前有时必须 git add

处理冲突

  1. git pull 获取最新内容
  2. git status查看当前状况(查看什么文件发生冲突)
  3. vi index.html(解决冲突内容)
  4. git add index.html
  5. git commit
  6. git push

不用/用promise实现ajax

不用promise实现ajax

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title></title>
  <style>
    .output{
      border: 1px solid black;
      min-height: 100px;
    }
  </style>
</head>
<body>
  <button id=myButton>AJAX to x</button>
  <button id=myButton2>AJAX to y</button>
  <div class="output" id="x"></div>
  <div class="output" id="y"></div>
  <script>
    let myButton = document.querySelector('#myButton')
myButton.onclick = function(){
  ajax({
    method: 'GET',
    success: function(responseText){
      document.querySelector('#x').innerText = responseText
    }
  })
}

let myButton2 = document.querySelector('#myButton2')
myButton2.onclick = function(){
  ajax({
    method: 'GET',
    url: '/y2',
    success: function(responseText){
      document.querySelector('#y').innerText = responseText
    }
  })
}

function commonErrorFn(status){
  alert('请求失败,状态码为' + status)
}

function ajax(options){
  let {method, url, success, error} = options
  if(!method){ throw new Error('你神经病,怎么不传 method') } 
  url = url || location.href
  let xhr = new XMLHttpRequest()
  xhr.open(method, url)
  xhr.onreadystatechange = function(){
    if(xhr.readyState === 4){
      if(xhr.status>=200 && xhr.status < 400){
        success && success.call(null, xhr.responseText, xhr)
      }else if(xhr.status >= 400){
        error && error.call(null, xhr.status, xhr)
      }
    }
  }
  xhr.send()
}

  </script>
</body>
</html>

用promise实现ajax

this

为何引入this

为了让函数和对象的属性有一个纽带,并且能自动传第一个参数。具体理解见下图:

什么是this

this 就是你call后面的第一个参数 (即call 一个函数时,传入的 context)。

如何看this表示什么参数

如果你的函数调用形式不是 call 形式,请按照将其转换为 call 形式。

JS(ES5)里面有三种函数调用形式:

1. func(p1, p2) 
2. obj.child.method(p1, p2)
3. func.call(context, p1, p2) // 先不讲 apply

第三种调用形式,才是正常调用形式
其他两种都是语法糖,可以等价地变为 call 形式:

func(p1, p2) 等价于func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等价于obj.child.method.call(obj.child, p1, p2)

所以上面三个this分别是window(后面讲),obj.child,context。

func(p1, p2) 中的 this 如何确定

function func(){
  console.log(this)
}

func()

等价于

function func(){
  console.log(this)
}

func.call(undefined) // 可以简写为 func.call()

按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:

如果你传的 context 就 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

因此上面的打印结果是 window。

obj.child.method(p1, p2) 的 this 如何确定

var obj = {
  foo: function(){
    console.log(this)
  }
}
obj.foo() 

按照「转换代码」,我们将 obj.foo() 转换为
obj.foo.call(obj)
好了,this 就是 obj。搞定。

具体题目使用

var obj = {
  foo: function(){
    console.log(this)
  }
}

var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window

请解释最后两行函数的值为什么不一样。
答案:

var obj = {
  foo: function(){
    console.log(this)
  }
}

var bar = obj.foo
obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj
bar() 
// 转换为 bar.call()
// 由于没有传 context
// 所以 this 就是 undefined
// 最后浏览器给你一个默认的 this —— window 对象

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.