This指向
this绑定优先级
显式绑定 > 隐式绑定 > 默认绑定
new绑定 > 隐式绑定 > 默认绑定
this默认绑定
this默认绑定我们可以理解为函数调用时无任何调用前缀的情景
,它无法应对我们后面要介绍的另外四种情况,所以称之为默认绑定,
1.默认绑定时this指向全局对象(非严格模式):
function fn1() {
let fn2 = function () {
console.log(this); //window
fn3();
};
console.log(this); //window
fn2();
};
function fn3() {
console.log(this); //window
};
fn1();
2.在严格模式环境中,默认绑定的this指向undefined
function fn() {
console.log(this); //window
console.log(this.name);
};
function fn1() {
"use strict";
console.log(this); //undefined
console.log(this.name);
};
var name = '听风是风';
fn();
fn1() //TypeError: Cannot read property 'a' of undefined
函数以及调用都暴露在严格模式中的例子:
"use strict";
var name = '听风是风';
function fn() {
console.log(this); //undefined
console.log(this.name);//报错
};
fn();
3.在严格模式下调用不在严格模式中的函数,并不会影响不在严格模式中的函数的this指向
var name = '听风是风';
function fn() {
console.log(this); //window
console.log(this.name); //听风是风
};
(function () {
"use strict";
fn();
}());
this隐式绑定
1.如果函数调用时,前面存在调用它的对象,那么this就会隐式绑定到这个对象上
function fn() {
console.log(this.name);
};
let obj = {
name: '听风是风',
function: fn
};
obj.function() //听风是风
2.如果函数调用前存在多个对象,this指向距离调用自己最近的对象
function fn() {
console.log(this.name);
};
let obj = {
name: '行星飞行',
function: fn,
};
let obj1 = {
name: '听风是风',
o: obj
};
obj1.o.function() //行星飞行
那如果我们将obj对象的name属性注释掉,现在输出什么呢?
function fn() {
console.log(this.name);
};
let obj = {
function: fn,
};
let obj1 = {
name: '听风是风',
o: obj
};
obj1.o.function() //??
这里输出undefined,大家千万不要将作用域链和原型链弄混淆了,obj对象虽然obj1的属性,但它两原型链并不相同,并不是父子关系,由于obj未提供name属性,所以是undefined。
既然说到原型链,那我们再来点花哨的,我们再改写例子,看看下面输出多少:
function Fn() {};
Fn.prototype.name = '时间跳跃';
function fn() {
console.log(this.name);
};
let obj = new Fn();
obj.function = fn;
let obj1 = {
name: '听风是风',
o: obj
};
obj1.o.function() //?
这里输出时间跳跃,虽然obj对象并没有name属性,但顺着原型链,找到了产生自己的构造函数Fn,由于Fn原型链存在name属性,所以输出时间跳跃了。
隐式丢失
在特定情况下会存在隐式绑定丢失的问题,最常见的就是作为参数传递以及变量赋值
参数传递时隐式丢失
这个例子中我们将 obj.fn 也就是一个函数传递进 fn1 中执行,这里只是单纯传递了一个函数而已,this并没有跟函数绑在一起,所以this丢失这里指向了window。
var name = '行星飞行';
let obj = {
name: '听风是风',
fn: function () {
console.log(this.name);
}
};
function fn1(param) {
param();
};
fn1(obj.fn);//行星飞行
变量赋值时的隐式丢失:
var name = '行星飞行';
let obj = {
name: '听风是风',
fn: function () {
console.log(this.name);
}
};
let fn1 = obj.fn;
fn1(); //行星飞行
隐式绑定丢失并不是都会指向全局对象
var name = '行星飞行';
let obj = {
name: '听风是风',
fn: function () {
console.log(this.name);
}
};
let obj1 = {
name: '时间跳跃'
}
obj1.fn = obj.fn;
obj1.fn(); //时间跳跃
this显式绑定
显式绑定是指我们通过call、apply以及bind方法改变this的行为
方法 | 参数 | 返回值 | 是否调用 |
---|---|---|---|
function.call(thisArg, arg1, arg2, ...) | thisArg(必选) 指定 function 函数的 this 非严格模式下指定为 null 或 undefined 时会自动替换为指向全局对象arg1, arg2, ...(可选) 传给function的参数,如果该参数的值为 null 或 undefined ,则表示不需要传入任何参数 |
谁调用call返回谁的返回值 | 会立即调用function |
function.apply(thisArg, [argsArray]) | 和call类似,唯一区别就是[argsArray] 参数是一个数组或者类数组,其中的数组元素将作为单独的参数传给 function 函数 |
谁调用apply返回谁的返回值 | 会立即调用function |
function.bind(thisArg,[arg1, arg2, ...]) | 参数和apply一样 | 返回改变了this指向后的function的拷贝 | 不会调用fuction |
new绑定
this指向通过new调用产生的构造函数的实例
function fn(){
console.log(this)
}
let person=new fn(); //this==>person
构造函数内部有return时,如果return的是基本数据类型,则仍然返回实例对象,如果return的是引用数据类型,则返回return的引用数据类型
箭头函数的this指向
箭头函数不会创建自己的this,它只会从自己作用域的上一层继承this
总结
1.this默认指向全局对象,严格模式下指向undefined
2.在严格模式中调用非严格模式函数不会影响非严格模式函数的this指向;反之亦然
3.在函数调用中,this指向距离自己最近的对象,即点前面那个对象(o.fu()指向o,obj.o.fun()指向o
)
4.把函数作为值时,会发生隐式绑定丢失,比如将函数赋值给一个变量,谁调用这个变量函数的this就指向谁(同第三点)
5.自调用函数this指向全局
6.new关键字创建的函数,this指向新创建的构造函数的实例
7.显示绑定的this指向call,apply,bind第一个参数指向的对象
8.箭头函数不会创建自己的this,它只会从自己的作用域的上一层继承this
9.事件绑定方法中this指向绑定事件的对象
番外:作用域链与原型链的区别
当访问一个变量时,解释器会先在当前作用域查找标识符,如果没有找到就去父作用域找,作用域链顶端是全局对象window,如果window都没有这个变量则报错。
当在对象上访问某属性时,首选i会查找当前对象,如果没有就顺着原型链往上找,原型链顶端是null,如果全程都没找到则返一个undefined,而不是报错。