携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第 17 天,点击查看活动详情
start
- 写一写 this 指向的问题。
问题
有个小伙伴,遇到过这么一个问题:
<!DOCTYPE html>
<html lang="en">
<body>
<div id="tomato">this指向</div>
<script>
document.getElementById('tomato').addEventListener('click', function () {
console.log('你好', this)
})
</script>
</body>
</html>
请问 这里的 this 指向谁?
答:这里的 this 指向
<div id="tomato">this指向</div>
小伙伴写这一串代码,写在的是Vue中,然后通过 this 获取data的数据,无法获取。其实弄清楚 这个地方的 this ,问题就很好解决了。
说说 this 指向
总共五种情况:
- 默认绑定
- 隐式绑定
- 显示绑定
- new 绑定
- 箭头函数
1. 默认绑定
考虑下面代码:
function foo(){
var a = 1 ;
console.log(this.a);
}
var a = 10;
foo();
这种 foo()
自己执行的情况,就是默认绑定,默认绑定this指向为 window,严格模式下为 undefined ;
所以这里的this指向window,window.a,所以打印10
2. 隐式绑定
function foo(){
console.log(this.a);
}
var obj = {
a : 10,
foo : foo
}
foo(); // ?
obj.foo(); // ?
谁调用函数,函数的this就指向谁
- 第一个打印,上一点讲过了,打印 undefined
- 第二个打印,就是 隐式绑定,
obj.foo();
obj调用的foo,所以this指向obj,所以打印 obj.a
3. 显示绑定
除了上面的两种,我们可以手动的指定 this。主要使用:call apply bind
,这三个函数都可以将 this指向他们第一个参数。
function foo() {
console.log(this.a)
}
var obj = {
a: 10,
foo: foo,
}
foo() // undefined
obj.foo() // 10
foo.call({ a: '使用call' }) // 使用call
foo.apply({ a: '使用apply' }) // 使用apply
var bn = foo.bind({ a: '使用bind' })
bn() // 使用bind
4. new 绑定
function foo() {
this.a = 10
console.log(this)
}
foo()
console.log(window.a)
var obj = new foo()
console.log(obj.a)
其实了解new 关键词做了什么,new的this指向就很清晰了。
new关键词做了:
- 创建一个新对象。
- 把这个新对象的
__proto__
属性指向 原函数的prototype
属性。(即继承原函数的原型) - 将这个新对象绑定到 此函数的this上 。
- 返回新对象,如果这个函数没有返回其他对象。
所以 new 的时候,此函数的this指向新生成的对象。
foo()
自己调用,所以此时的this执行 window,所以 window.a =10 ,第一个打印 window第二个打印,因为上一句foo(),修改了window,所以此时 window.a是 10 ,第二个打印10
new foo()
可以理解为:
this={} this.a = 10 console.log(this) obj=this
所以
new foo()
会先打印 {a:10}
- 第四个打印 10
5. 箭头函数
箭头函数它没有自己的this
对象,内部的this
就是定义时上层作用域中的this
。
例如将问题中的写法改成箭头函数,此时this就指向window,而不是dom对象了:
document.getElementById('tomato').addEventListener('click', ()=>{
console.log('你好', this)
})
6.优先级
优先级依次为:
箭头函数》new 绑定》显示绑定》隐式绑定》默认绑定
练习
才学习完毕,来几个热乎的题目熟悉熟悉
注意:下列题目的运行环境,若无特殊说明,皆为非严格模式
题目一
题目:
var name = "window";
var person = {
name: "person",
sayName: function () {
console.log(this.name);
}
};
function sayName() {
var sss = person.sayName;
sss();
person.sayName();
(person.sayName)();
(b = person.sayName)();
}
sayName();
解析:
其实考察的就是默认绑定和隐式绑定,这里的sss其实存储的就是 function () { console.log(this.name); }
的引用地址,所以就类似于foo()
,所以它的this指向window
答案:
window
person
person
window
题目二
var name = 'window'
var person1 = {
name: 'person1',
foo1: function() {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function() {
return function() {
console.log(this.name)
}
},
foo4: function() {
return () => {
console.log(this.name)
}
}
}
var person2 = { name: 'person2' }
person1.foo1()
person1.foo1.call(person2)
person1.foo2()
person1.foo2.call(person2)
person1.foo3()()
person1.foo3.call(person2)()
person1.foo3().call(person2)
person1.foo4()()
person1.foo4.call(person2)()
person1.foo4().call(person2)
解析:
这道题其实考察的就是,隐式绑定,显示绑定,箭头函数。
**箭头函数它没有自己的this
对象,内部的this
就是定义时上层作用域中的this
。**所以在上述代码中 foo4
中的箭头函数 this 指向一直跟随 foo4这个函数的this。
答案:
person1
person2
window
window
window
window
person2
person1
person2
person1
end
- 回头再来看小伙伴遇到的问题,很简单有没有。
- 想要正确的获取外部的this,解决方案:1.可以使用箭头函数;2.外部定义一个变量存储this,传入进来即可。