前言
this 在 JS 是一个很重要的部分,在学习和实战都能经常用到。在前端面试中,this 也是一个经常被问到的考点,它的作用,就是以一个优雅的方式隐式传递了一个对象的引用,提高了代码的复用性,这也是为什么要用 this。重点,就是了解 this 的绑定规则,才能更好的在实战开发中运用。
this 的绑定规则
1>默认规则
函数直接使用不带任何修饰的函数引用进行调用(独立函数调用),this默认绑定全局对象Window
*注:严格模式下,不能将全局对象用于默认绑定,因此this会绑定到 undefined
function foo(){
var a = 1
console.log(this.a);//2
}
var a=2
foo()
上面代码 foo 函数在全局直接调用,因此只能使用默认绑定,this指向全局对象window,所以,打印a=2
2>隐式绑定
当函数被某个对象拥有时(函数被引用到对象),此时函数引用有上下文对象,触发隐式绑规则:会把函数中的this绑定到对象(上下文对象)当中
function foo(){
console.log(this.a); //2
}
var obj = {
a: 2,
foo: foo //如果是foo(),就不是引用,不被拥有,this指向window对象,打印undefined
}
obj.foo()
*注:对象属性引用链只有上一层或者说最后一层在调用位置起作用
function foo(){
console.log(this.a); //42
}
obj1 ={
a :42,
foo:foo
}
obj2 = {
a:2,
obj2:obj1
}
obj2.obj2.foo()
以上代码,函数foo被引用在obj1中,而obj1被引用在obj2中,调用时还是在最后一层(obj1)中起作用,this指向直接引用自己的对象obj1
3>隐式丢失
多次引用函数,最终函数调用前没有上下文对象,就会造成隐式丢失,从而走默认绑定规则(是一种现象)
function foo(){
console.log(this.a); //1
}
var a = 1 //全局对象属性
var obj = {
a:2,
foo:foo
}
var bar = obj.foo;//隐式丢失
bar() //即foo()
以上代码,函数foo被对象obj引用后,bar再次引用obj.foo,实际上bar引用的就是foo函数本身,此时bar的调用就是foo的直接调用,是不带任何修饰的函数调用,因此引用默认绑定,从而this绑定到全局对象或者undefined(取决于是否是严格模式)
*注:如果多次引用后,仍然被一个对象所拥有,此时函数引用仍然有上下文对象,就不会发生隐式丢失,就还是隐式绑定
function foo(){
console.log(this.a); //3
}
var a = 1
var obj = {
a:2,
foo:foo
}
var bar = {
a:3,
bar:obj.foo
}
bar.bar()
4>显示绑定
通过调用辅助函数,修改函数this的指向,主要有call、apply、bind方法
function foo(){
console.log(this.a);
}
var obj = {
a:2
}
foo.call(obj) //2
foo.apply(obj) //2
var bar = foo.bind(obj) //2
bar()
区别:
- call 修改函数的this指向,接受零散的参数
- apply 修改函数的this指向,参数以数组的形式接受
- bind 修改函数的this指向,会返回一个新的函数,接受零散的参数
function foo(x,y){
console.log(this.a,x+y);
}
var obj = {
a:2
}
foo.call(obj,1,2) //2 3
foo.apply(obj,[1,2]) //2 3
var bar = foo.bind(obj,2,3)
bar() //2 5
var bar = foo.bind(obj)
bar(2,3) //2 5
*注:当调用这三个函数时不传递参数,或者传递null为参数,那么函数的this会指向window
这三种方法在面试时也会经常被要求手写实现,主要就是实现修改this指向,和考虑到传递的参数情况,需要我们手写的函数和它们具有完全一样的功能特征
5>new 绑定
当使用new来调用函数时,即发生构造函数调用时,新的实例对象会被绑定到构造函数的this上,即this指向实例对象
function foo(a){
this.a = a
}
var bar = new foo(2)
console.log(bar.a) //2
优先级
new绑定 > 显示绑定 > 隐式绑定 > 默认绑定
箭头函数this指向问题
箭头函数本身没有this这个概念,写在其内部的this,也就是其外部的普通函数的this
function foo(){
// this
var bar = () => {
var baz = () => {
console.log(this.a) //相当于直接写在foo里的this
}
}
}