this的概念一共可以分为五种场景:
- 默认绑定
- 隐式绑定
- 显式绑定
- new绑定
- 箭头函数绑定
1、this的默认绑定
在函数调用没有任何前缀的时候,就属于this默认绑定。
function fn3() {
console.log(this); //window
};
f3();
在这段代码中,函数调用没有任何前缀,没有指定任何对象,那么this指向全局对象window。
注意:在严格模式下,默认绑定的this指向undefined,代码如下
function fn1() {
console.log(this); //window
};
function fn2() {
"use strict"; //在严格模式
console.log(this); //undefined
};
fn1();
fn2();
上面这个例子是在fn2的本地执行上下文里面使用"use strict",如果说是fn2函数外面使用严格模式将函数包裹住,那么与使用在里面的效果是相同的。
this的隐式绑定
在函数被调用之前,如果前面存在调用它的对象,那么this就会隐式绑定到这个对象上。
function fo() {
console.log(this.name);
};
let obj = {
name: 'henu_GM',
fo: fo
};
obj.fo();
如果函数调用前存在多个对象,那么this指向距离自己调用最近的对象,采取就近原则。
function fo() {
console.log( this.a );
}
var a = 7;
var obj1 = {
a: 4,
fo: fo
};
var obj2 = {
a: 3,
obj1: obj1
};
obj2.obj1.fo(); // 4
注意:在特定情况下会发生隐式绑定丢失的问题,其中最主要的两个问题
1、将含this的函数作为参数传递给了另一个函数,这里的this并没有与之前那个函数绑定,而是与调用之前那个函数的对象隐式绑定,所以这里this脱离了绑定对象,this指向window;
2、对已经隐式绑定了的函数进行变量赋值,在用新的变量调用这个函数,也会造成this指向window。
就这么说吧,把函数作为参数进行传递给其他函数或者对象,如果接收的是一个新的对象,那么这个函数的this就指向新的对象,如果接收的是函数一类的,那么就直接指向window
this的显式绑定
显式绑定不同于隐式,显式绑定是指我们通过call,apply以及bind方法改变this的行为。
通俗来讲,call和appply让函数从被调用变为主动选择自己的上下文,称为函数应用。
需要注意的是,无论是call还是apply,亦或是bind,如果选择的参数是undefined或者null那么this将指向全局变量。
this的new绑定
JavaScript中的构造函数,它只是使用new调用的一个普通函数,而并不是一个类,最终返回的对象也不是一个实例。
那么new一个函数究竟发生了什么:
- 以构造器的
prototype属性为原型,创建对象。 - 将
this和调用参数传给构造器。 - 如果构造器没有手动返回对象,则返回第一步创建的对象。
则叫做,构造调用。
那么就可以这么理解,this的new绑定无非是创建一个对象是要调用的一个函数,而这个要使用到的构造函数的this在调用的过程中指向发起这次构造的对象,这就是this的new绑定了。
箭头函数的this绑定
箭头函数ES6新增的属性,箭头函数中没有this,箭头函数的this指向外层作用域中的this,外层作用域或者函数的this指向谁,箭头函数中的this就指向谁。
有一点要注意,this的绑定类似于bind的硬绑定(call和apply失效),就是说,一旦箭头函数的this绑定成功,就无法被再次改变。如果必需要改变的话,我们可以直接改变箭头函数的外层作用域的this指向,也可以。
this五种绑定方法的优先级
显式绑定 > 隐式绑定 > 默认绑定
new绑定 > 隐式绑定 > 默认绑定
据说new绑定是优先于显示绑定的,我试了一下,发现new的使用和显示绑定完全不在一个场景,不能判断它俩的优先级。