本章解决问题:
1. this是什么,为何引入?
2. 关于this的误解
3. this绑定规则和判定
4. 箭头函数的this绑定

1、this是什么,为何引入?

答:

  • 本质:this是JS中的一个关键字;
  • 作用:this的作用是通过指向来传递对象的引用;
  • 为何引入:为了更优雅的传递对象的使用;
  • 如何使用:只有函数才有this相关概念,this的指向完全取决函数的调用方式;
  • 注意点:
1)this是在运行时绑定的,而非编写时;
2)this的绑定只与函数调用方式有关,与申明无任何关系;

2、目前关于this指向有何误解?

答:
  1. this并不是指向函数的调用者:
    -也就是说this并不是单纯的指向它的调用者,而是依靠一定的绑定规则进行优先级的比较,最终决定this的绑定;
  2. this并不指向函数本身: (以下面的一个例子为例)
    -如果this指向的是fn,那么最终的cnt应该是2,但结果确是0;
    -实际这里的this绑定的是widows对象,所以没改变fn的count;
function fn () {
    this.count ++ ;
}
fn.count = 0;

for(let i = 0;i<5;i++){
    if(i > 2) {
        fn(i);
    }
}

console.log(fn,count);  // 0

3、this绑定规则

答:
1)默认绑定:

当前执行函数没有调用它的对象时,this指向全局对象,在浏览器中就是Window对象(非strict)
注意:必须是对象调用函数!如果函数调用函数,等同于没调用;

代码0中:函数调用带this函数,this永远指向Window全局;
2)隐式绑定:

  当函数前面有调用它的对象时,this指向调用函数最近的对象

2.1)隐式绑定的丢失

  在特殊情况下隐式绑定会丢失,最常见的两种:作为参数传递和最为变量赋值;
  丢失后的绑定规则:
        若作为函数参数传递丢失,this直接指向Window全局对象(非严),与函数this无关;
        若变量赋值后丢失,this重新寄托在新变量上;
  - 代码1中:作为参数传递丢失,重新定位在fn1上,所以this指向Window;
  - 代码2中:变量赋值丢失,重新定位在fn上;
  - 代码3中:带this的函数作为setTimeout的参数传递,this指向Window对象;

3)显式绑定

    就是使用call()apply()和bind()方法手动的改变this的指向;
  - 代码4中:自己改变this的指向并调用函数;
  - 注意:
        若第一个参数是null/undefind,默认指向Window全局对象;
        apply和call改变完this后会执行函数,而bind只会返回改变完this的新函数;

4)new绑定

    当new来实现构造函数调用时,依次执行以下几步:
   1. 创建(或者说构造)一个全新的对象。
   2. 这个新对象会被执行[[原型]]连接。
   3. 这个新对象会绑定到函数调用的this。
   4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
   其中的第三步,就是把构造函数的this绑定到新的实例对象上并调用,实现属性和方法的继承;
  - 代码5中:new的过程中this绑定到echo上,因此echo上出现了name属性;

5)4个绑定的优先级:

    new绑定 > 显式绑定 >  隐式绑定 > 默认绑定;
//代码0
var a = 1
function foo () {
  var a = 2
  function inner () { 
    console.log(this.a)
  }
  inner()
}

foo()
//代码1
var name = '行星飞行';
let obj = {
    name: '听风是风',
    fn: function () {
        console.log(this.name);
    }
};

function fn1(param) {
    param();
};
fn1(obj.fn);//行星飞行
//代码2
var name = '行星飞行';
let obj = {
    name: '听风是风',
    fn: function () {
        console.log(this.name);
    }
};
let obj1 = {
    name: '时间跳跃'
}
obj1.fn = obj.fn;
obj1.fn(); //时间跳跃
//代码3
var obj1 = {
  a: 1
}
var obj2 = {
  a: 2,
  foo1: function () {
    console.log(this.a)
  },
  foo2: function () {
    setTimeout(function () {
      console.log(this)
      console.log(this.a)
    }, 0)
  }
}
var a = 3

obj2.foo1() //2
obj2.foo2() //3
// 代码4
let obj1 = {
    name: '听风是风'
};
let obj2 = {
    name: '时间跳跃'
};
var name = '行星飞行';

function fn() {
    console.log(this.name);
};
fn.call(undefined); //行星飞行
fn.apply(null); //行星飞行
fn.bind(undefined)(); //行星飞行
//代码5
function Fn(){
    this.name = '听风是风';
};
let echo = new Fn();
echo.name//听风是风

4、箭头函数的this绑定

答:

箭头函数相关记住几个规则:
    1)箭头函数本身无this,它的this 找上层最接近的作用域的this(就是找上层函数);
    2) 箭头函数的this指向的是函数定义时的this,而非执行时(看准何时定义);
    3)call、apply和bind无法改变箭头函数this的指向;

白衣黑月
32 声望1 粉丝