JavaScript:this的指向
2021-05-08 本文已影响0人
前小小
this 的默认绑定
- 全局环境下的 this 指向了 window
console.log(this); // window
- 函数独立调用,函数内部的 this 也指向了 window,函数默认被挂载到 window 上
function fn() {
console.log(this);
}
fn(); // window // 相当于window.fn();
- 被嵌套函数独立调用时,this 默认指向了 window
var obj = {
a: 2,
// 函数当做对象的方法来调用 this指向了obj
fn: function () {
function test() {
console.log(this); // window
}
test();
},
};
obj.fn(); // 此时test()函数自己去执行,相当于函数独立调用, 所以此时的this也是window
- 立即执行函数的 this 指向 window
(function () {
console.log('自执行函数中内部的this: ' + this); //window
})();
- 闭包中 this 默认指向了 window
// 闭包就是能够读取其他函数内部变量的函数。下面的test函数就是闭包
var a = 0;
var obj = {
a: 2,
foo: function () {
var c = this.a;
return function test() {
console.log(this); // window
return c;
};
},
};
var fn = obj.foo();
console.log(fn()); // 2
- 函数调用链(一个函数又调用另外一个函数),此时每个函数相当于独立调用,this 指向 window
function test1() {
console.log(this); // window
test2();
}
function test2() {
console.log(this); // window
}
test1();
- 内置函数 setTimeout()和 setInterval()第一个参数的回调函数中的 this 默认指向了 window
// 1.
setTimeout(function () {
console.log(this); // window
}, 1000);
// 2.
var a = 10;
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo,
};
setTimeout(obj.foo, 1000); // 10
// 以上代码相当于
setTimeout(function foo() {
console.log(this.a);
}, 1000); // 10
this 的隐式绑定
// 1. 当函数当做对象的方法来调用,this指向了直接对象
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo,
obj2: {
a: 2,
foo: foo,
},
};
// foo()函数的直接对象是obj, this会隐式的被绑定到obj对象上
obj.foo(); // 1
// foo()函数的直接对象是obj2, this会隐式的被绑定到obj对象上
obj.obj2.foo(); // 2
this 的显示绑定
- 通过 call() apply() bind() 绑定 this 对象
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
};
foo(); // 0
foo.call(obj); // 2
foo.apply(obj); // 2
var fn = foo.bind(obj);
fn(); // 2
- 如果 this 被硬绑定, 那么 this 不能再被改变
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 2,
};
var bar = function () {
foo.call(obj);
};
bar();
setTimeout(bar, 2000);
// 硬绑定后bar无论怎么调用,都不会影响foo函数的this绑定
bar.call(window); // 2
- 数组的 forEach (还有 map() filter() some() every()等函数)
// 因为默认情况下传入的函数是独立调用的(默认绑定)
var id = 'window';
var obj = {
id: 'fn',
};
var arr = [1, 2, 3];
arr.forEach(function (item) {
console.log(item, this.id); // 打印了三次"window"
});
// 如果要改变该函数的this指向, 就给forEach的第二个参数传递一个对象
var id = 'window';
var obj = {
id: 'fn',
};
var arr = [1, 2, 3];
arr.forEach(function (item) {
console.log(item, this.id); // 打印了三次"fn"
}, obj);
this 的 new 绑定
// 如果是new关键字来调用函数 相当于构造函数来实例化对象,那么内部的this指向了当前实例化的对象
// 创建Person
function Person() {
console.log(this); // Person {}
}
var p = new Person();
console.log(p); // Person {}
this 的隐式丢失
- 函数别名
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo,
};
obj.foo(); // 1
// 因为foo最终被调用的位置是bar,而bar在进行调用时没有绑定任何的对象,也就没有形成隐式绑定,此时为默认绑定情况,里面的this指向了window
var bar = obj.foo;
bar(); // 0
- 参数传递
var a = 0;
function foo() {
console.log(this.a);
}
var obj = {
a: 1,
foo: foo,
};
obj.foo(); // 1
// 因为foo最终被调用的位置是bar,而bar在进行调用时没有绑定任何的对象,也就没有形成隐式绑定,此时为默认绑定情况,里面的this指向了window
var bar = obj.foo;
bar(); // 0
- 间接调用
function foo() {
console.log(this.a);
}
var a = 2;
var obj = {
a: 3,
foo: foo,
};
var p = { a: 4 };
// 隐式绑定,函数当做对象中的方法来使用,内部的this指向了该对象
obj.foo(); // 3
// 赋值(obj2.foo = obj1.foo)的结果是foo函数;
// foo函数被直接调用,那么是默认绑定
(p.foo = obj.foo)(); // 2
// 将obj.foo函数赋值给p.foo函数, 之后p.foo()函数再执行,其实是属于p对象的方法的执行,this指向了当前的p对象
p.foo = obj.foo;
p.foo(); // 4
ES6 箭头函数中的 this 指向
MDN 官方文档:「箭头函数不会创建自己的 this,它只会从自己的作用域链的上一层继承 this。」
var obj = {
a: () => {
console.log(this);
},
};
// 对象是不能产生作用域的,a方法实际是被定义在了全局作用域下,里面的this指向的是window
obj.a(); // window
// 不能用call方法改变箭头函数的this指向
var obj = {
a: () => {
console.log(this);
},
};
obj.a.call({ name: 'zhangsan' }); // window
严格模式下的 this 指向
// 1. 严格模式下, 独立调用的函数内部的this指向了undefined
function fn() {
'use strict';
console.log(this); // undefined
}
fn();
// 2. 严格模式下, 函数apply()和call()内部的this始终是它们的第一个参数
function fn() {
'use strict';
console.log(this); // 第一个输出null,第二句输出undefined
}
showColor.call(null);
showColor.call(undefined);