最近看到了面试题目有关于this指向的问题,网上搜了一篇文章,看了之后受益匪浅,特地总结一下。
原文章链接:前端面试中的“this”,你真的了解吗? - 哔哩哔哩
什么是this?
this是一个特殊的关键字,其值由运行时根据函数的执行环境绑定。
也就是说,this指向当前执行环境,可以使用其动态访问运行到其所在代码时候的所有变量
this的约束规则
1.默认的this指向window
这里没什么好说的,你在全局环境下使用的this,就是window对象
2.独立的函数调用,指向window
我们来对比一下,什么是独立和非独立
// 非独立函数 需要初始化,不存在变量提升
var a = function() {
console.log("xxxx")
}
// 独立函数 存在变量提升 this指向window
function a() {
console.log("xxxx")
}
function a() {
console.log('xxxxx',this);
return function b() {
console.log('yyyyy',this);
return function c() {
console.log('zzzzz',this);
}
}
}
a()()()
可以看到,独立函数调用不管多深都是指向window
3.自执行函数调用,指向window
// exp1
(function () {
console.log(this); // Window
})()
// exp2
var a = 10
function foo() {
(function son(that) {
console.log(this); // Window
console.log(that); // {a: 20, foo: ƒ}
})(this) // 自执行函数后面加个()表示立即执行 ()里面可以塞入参数
}
var obj = {
a: 20,
foo: foo,
}
obj.foo()
4.闭包当中的this,指向window
var a = 10
var obj = {
a: 20,
foo: function () {
var sum = this.count + 10
console.log('xxxxx',this.count,sum);
console.log(this.a); // 20
return function () {
console.log(this.a); // 10
return sum
}
}
}
console.log('xxxxx',obj.foo()() );
5.函数作为方法调用时,this指向函数的直接父对象
var a = 10
function foo () {
console.log(this.a);
}
var obj = {
a: 20,
foo: foo,
obj2: {
a: 30,
foo: foo
}
}
// exp1
foo() // 10
// exp2
obj.foo() // 20
// exp3
obj.obj2.foo() // 30
隐式绑定丢失
1.隐式绑定的函数被分配为没有 this 指向的变量
var a = 10
var obj = {
a: 20,
foo: function () {
console.log(this.a);
}
}
function bar (fn) {
fn()
}
bar(obj.foo) // 10
2.隐式绑定的函数作为参数传给函数,丢失了this点
var a = 10
var obj = {
a: 20,
foo: function () {
console.log(this.a);
}
}
function bar (fn) {
fn()
}
bar(obj.foo) // 10
原作者应该写错了??这两个代码一模一样,我没太看懂???
3.setTimeout和setInterval函数的隐式绑定丢失
// exp1
setTimeout(function() {
console.log(this); // Window
}, 1000)
// exp2
var a = 10
var obj = {
a: 20,
foo: function () {
console.log(this.a); // 10
}
}
setTimeout(obj.foo, 1000)
值得注意的是,这两个函数是可以传递this上下文的,只要我们将setTimeout函数的第一个参数写成箭头函数即可。
也就相当于,在这里匿名function的行为和非独立函数调用不一样,但是可以使用匿名箭头函数来实现该效果。
显式绑定
我们使用call ,apply,bind来显式绑定this的环境
var obj = {
ttt: 'my name',
}
function test(v1,v2) {
this.v1 = v1
this.v2 = v2
console.log('xxxxx',this.ttt);
}
test('a','b')
console.log('xxxxx',obj);
test.call(obj,'a','b')
console.log('xxxxx',obj);
test.apply(obj,['c','d'])
console.log('xxxxx',obj);
test.bind(obj,'e','f')()
console.log('xxxxx',obj);
关于硬装订和new绑定,暂时没研究,感兴趣的读者可以前往原链接看看!