这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战
hi 我是小十七_,之前总结过一些函数 this 指向的判断方式,分享给大家~
函数 this 指向的判断方式有四种:
默认绑定
function foo(){
console.log(this.a);
}
foo(); // undefined
foo 在 window 下被调用,this 指向 window(严格模式下为 undefined)
function foo(){
'use strict';
console.log(this.a);
}
foo(); // TypeError: Cannot read property 'a' of undefined
隐式绑定
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
obj.foo(); // 2
this 指向直接调用它的对象
// 一个反例
function foo(){
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
}
setTimeout(obj.foo, 1000); // undefined
// setTimeout 只是通过 obj.foo 拿到了 foo 函数的引用,实际调用 foo 函数是在 window 下
显式绑定
function foo() {
console.log(this.a);
}
var obj = {
a: 2
}
foo.call(obj); // 2
硬绑定
call 和 apply 都会调用这个函数,将 this 绑定到第一个参数上
bind 会返回一个新函数,将新函数的 this 指向 call 到传入的第一个参数上(bind 的内部实现另外一篇还没写完)
new
function Foo(){
this.aaa = 123;
}
var bar = new Foo();
console.log(bar.aaa); // 123
如果没有被 new 调用,Foo 就是一个普通的函数,
被 new 调用之后,Foo 被称为构造函数,执行 new 操作时会干下面几件事:
- 创建一个全新的对象
- 这个新对象会被执行 [[ 原型 ]] 连接。(后面看原型补充)
- 这个对象被绑定到
Foo调用时的this - 如果
Foo没有返回其他对象,则new调用这个函数时会返回这个新对象
正常判断 this 指向优先级的过程是从后往前 new -> 显示 -> 隐式 -> 默认
绑定例外
- 把
null或undefined传入到call,apply或bind中时,函数会忽略this,从而变成默认绑定规则
function foo(){
console.log(this.a);
};
var a = 2;
foo.call(null);
如果不关心 this 指向的话,有两种情况会这样使用:
// 使用 apply 将数组展开,作为参数
function foo(a, b){
console.log(a, b);
}
foo.apply(null, [2, 3]); // 2 3
// 使用 bind 定义一些参数的默认值
function foo(a, b){
console.log(a, b);
}
var bar = foo.bind(null, 2);
bar(3); // 2 3
不过按照前面所说的,这种情况变成了默认绑定的规则,可能会污染全局变量,所以还是不要传 null 传占位的有意义的变量
function foo(a, b){
console.log(a, b);
}
// 定义一个空对象,和 {} 的区别是没有链接 Object 的原型
var emptyObj = Object.create(null);
foo.apply(emptyObj, [2, 3])
箭头函数
function foo(){
setTimeout(()=>{
console.log(this.a);
}, 1000)
}
var obj = {
a: 2
}
foo.call(obj); // 2
箭头函数的 this 指向只由外层函数决定,不应用上面说的4条绑定规则,并且一旦绑定就不会被直接修改(new 也不行)
function foo(){
return ()=>{
console.log(this.a);
}
}
var obj1 = {
a: 2
};
var obj2 = {
a: 3
}
var bar = foo.call(obj1); // foo 的 this 指向 2
bar.call(obj2); // 2
之前没有箭头函数时,用 var self = this; 或者 bind 来实现