JS深挖(this绑定问题详解)

本章解决问题: 1. this是什么,为何引入? 2. 关于this的误解 3. 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)

2)隐式绑定:
当函数前面有调用它的对象时,this指向调用函数最近的对象

2.1)隐式绑定的丢失
在特殊情况下隐式绑定会丢失,最常见的两种:作为参数传递和最为变量赋值; - 隐式绑定丢失时,this视为*寄托*在新的函数中重新定位,如下: - 代码1中:作为参数传递丢失,重新定位在fn1上,所以this指向Window; - 代码2中:变量赋值丢失,重新定位在fn上;

3)显式绑定
就是使用call()apply()和bind()方法手动的改变this的指向; - 代码3中:自己改变this的指向并调用函数; - 注意:若第一个参数是null/undefind,默认指向Window全局对象;

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

【JS深挖(this绑定问题详解)】5)4个绑定的优先级:
new绑定 > 显式绑定 >隐式绑定 > 默认绑定;

//代码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 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//听风是风

    推荐阅读