JavaScript-JS中this的指向

JavaScript-JS中this的指向

本文将主要总结JS中this的指向

隐式绑定的场景:

  • 全局上下文
  • 直接调用函数
  • 对象.方法的形式调用
  • DOM事件绑定(特殊)
  • new构造函数绑定
  • 箭头函数

1. 全局上下文

全局上下文默认this指向window, 严格模式下指向undefined。

2. 直接调用函数

比如:

let obj = {
  a: function() {
    console.log(this);
  }
}
let func = obj.a;
func();

这种情况是直接调用。this相当于全局上下文的情况(默认this指向window, 严格模式下指向undefined。)。

3. 对象.方法的形式调用

还是刚刚的例子,我如果这样写:

obj.a();

这就是对象.方法的情况,this指向这个对象

4. DOM事件绑定

onclick和addEventerListener中 this 默认指向绑定事件的元素。

IE比较奇异,使用attachEvent,里面的this默认指向window。

5. new+构造函数

此时构造函数中的this指向实例对象。

6. 箭头函数?

箭头函数没有this, 因此也不能绑定。里面的this会指向当前最近的非箭头函数的this,找不到就是window(严格模式是undefined)。比如:

let obj = {
  a: function() {
    letdo = () => {
      console.log(this);
    }
    do();
  }
}
obj.a(); // 找到最近的非箭头函数a,a现在绑定着obj, 因此箭头函数中的this是obj

显式绑定的场景:

call, apply, bind都是为了调用函数,然后改变函数中的this的指向。
它们允许你在调用函数时为函数指定上下文

1.call

  • call用于显式地设置函数的上下文,call方法将对象绑定到this。
  • call 需要分别传参
  • call会立即执行函数
function show(title) {
    alert(`${title+this.name}`);
}
let lisi = {
    name: '李四'
};
let wangwu = {
    name: '王五'
};
show.call(lisi, '后盾人'); //重点

2.apply

apply与call用于显式地设置函数的上下文,两个方法作用一样都是将对象绑定到this,只是在传递参数上有所不同。
因为,我们可以看到,call方法必须一个一个传递参数,这样有些恼人。如果我们可以把整个数组作为第二个参数并让 JavaScript 为我们自动展开就好了。
所以,这个时候apply,就派上用场了
apply 用数组传参
call 需要分别传参
与 bind 不同 call/apply 会立即执行函数

  • apply用于显式地设置函数的上下文,apply方法将对象绑定到this。
  • apply 需要分别传参
  • apply会立即执行函数
function show(title) {
    alert(`${title+this.name}`);
}
let lisi = {
    name: '李四'
};
let wangwu = {
    name: '王五'
};
show.apply(lisi, ['后盾人']); //重点

也就是说,apply和call如果不传参数的话,只传想要改变的this的指向,那他们用法,效果都是一样的。
func().call(self) //意思是将func()这个函数中的this指向self
func().apply(self) //意思是将func()这个函数中的this指向self

小栗子:
找数组中的数值最大值

let arr = [1, 3, 2, 8];
console.log(Math.max(arr)); //NaN
console.log(Math.max.call(Math, arr)); //NaN, 因为call除了要传的this以外,后面的参数必须用逗号隔开,现在传的是数组
console.log(Math.max.apply(Math, arr)); //8, apply后的参数传的是数组
console.log(Math.max(...arr)); //8, 当然我们用展开语法也是完全可以的

3.bind

bind()是将函数绑定到某个对象,比如 a.bind(hd) 可以理解为将a函数绑定到hd对象上即 hd.a()。
其实,.bind.call 完全相同,除了不会立刻调用函数,而是返回一个能以后调用的新函数。

与 call/apply 不同bind不会立即执行
bind 是复制函数行为,会返回新函数
bind是复制函数行为

let a = function() {};
let b = a;
console.log(a === b); //true
//bind是新复制函数
let c = a.bind();
console.log(a == c); //false

然后呢,因为调用bind方法并不会立即执行该函数,所以就给了我们两次传参的机会;
绑定参数注意事项

function func(a, b) {
  return this.f + a + b;
}

//使用bind会生成新函数
let newFunc = func.bind({ f: 1 }, 3);

//1+3+2 参数2赋值给b即 a=3,b=2
console.log(newFunc(2)); //注意如果在前面bind的时候给某些参数赋值过了,在这里就不需要赋值了,现在赋了也没用

优先级: new > call、apply、bind > 对象.方法 > 直接调用。

参考:

posted @ 2020-03-08 16:53  LSKReno  阅读(148)  评论(0编辑  收藏  举报