This
绑定规则
1 默认绑定;
2 隐式绑定;
3 硬绑定;
4 new 绑定;
默认绑定
一般是函数调用;比如定义在全局环境中的函数;调用的时候直接 fn();
在非严格环境下 ,this 是指向的全局对象(浏览器); 严格模式下,this 是指向 undefined(node 环境);
隐式绑定
函数的调用是在某个对象上触发的,即调用位置上存在上下文对象;典型的形式为 XXX.fun()
function sayHi(){
console.log('Hello,', this.name);
}
var person = {
name: 'YvetteLau',
sayHi: sayHi
}
var name = 'Wiliam';
person.sayHi();
打印的结果是 Hello,YvetteLau
因为只有最后一层会确定this指向的是什么,不管有多少层,在判断this的时候,我们只关注最后一层;
显式绑定
显式绑定比较好理解,就是通过call,apply,bind的方式,显式的指定this所指向的对象;
new 绑定
任何一个函数都可以使用new来调用,因此其实并不存在构造函数,而只有对于函数的“构造调用”;
使用new来调用函数,会自动执行下面的操作:
- 创建一个新对象
- 将构造函数的作用域赋值给新对象,即this指向这个新对象
- 执行构造函数中的代码
- 返回新对象
因此,我们使用new来调用函数的时候,就会新对象绑定到这个函数的this上
function sayHi(name){
this.name = name;
}
var Hi = new sayHi('Yevtte');
console.log('Hello,', Hi.name);
输出结果为 Hello, Yevtte, 原因是因为在var Hi = new sayHi('Yevtte');这一步,会将sayHi中的this绑定到Hi对象上。
绑定优先级
new绑定 > 显式绑定 > 隐式绑定 > 默认绑定
例外
如果我们将null或者是undefined作为this的绑定对象传入call、apply或者是bind,这些值在调用时会被忽略,实际应用的是默认绑定规则;
var foo = {
name: 'Selina'
}
var name = 'Chirs';
function bar() {
console.log(this.name);
}
bar.call(null); //Chirs
箭头函数
箭头函数 首先 是没有自己的 this 的;它的 this 是集成于外层代码库的中 this; 需要注意一下几点:
- 函数体内的this 对象 是继承的外层代码块的 this;
- 不可以做为构造函数, 即不可以使用 new 命令;? 因为没有 prototype,
- 不可以代替 arguments 对象; 该对象在函数体内不存在, 如果要用可以用 rest 参数代替;
- 不可以使用 yield,因此不能用作 Generator;
- 没有自己的 this,所以不能用 call(),apply(),bind() 这些方法 去改变 this 的指向;
总结
- 函数是否在new中调用(new绑定),如果是,那么this绑定的是新创建的对象。
- 函数是否通过call,apply调用,或者使用了bind(即硬绑定),如果是,那么this绑定的就是指定的对象。
- 函数是否在某个上下文对象中调用(隐式绑定),如果是的话,this绑定的是那个上下文对象。一般是obj.foo()
- 如果以上都不是,那么使用默认绑定。如果在严格模式下,则绑定到undefined,否则绑定到全局对象。
- 如果把Null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。
- 如果是箭头函数,箭头函数的this继承的是外层代码块的this。