一遍就明白this指向,代码剧情化

outside_default.png

我正在参加「掘金·启航计划」点击活动查看详情

this

搞明白this四种绑定规则以及优先级也就明白了this指向了。

  • new > 显式绑定 > 隐式绑定 > 默认绑定

默认绑定

  • 当独立函数调用时,不管是否在调用栈中,this都指向全局对象(浏览器中为window)

  • 严格模式下不能将全局对象用于默认绑定

// "use strict"  严格模式下this访问不到local:Uncaught TypeError
var local = 'earth'
function gps() {
    console.log(this.local);
}
function locate() {
    var local = 'China'
    gps()
}
locate()  //  earth    local:我有的不仅仅是中国,而是世界(haahaha)
复制代码

进一步解释独立函数调用。

function universe() {
    console.log(this);	//	Window
    earth()
}
function earth() {
    console.log(this);	//	Window
    china()
}
function china() {
    console.log(this);	//	Window
}
universe()  //   三个打印都是window对象。window: 只要你落单了,就要和我绑定。
复制代码

无论是这种链式的函数调用,亦或是作为参数传入函数中直接调用,还有以下这种情况。对象中的方法作为参数传入另一个函数中直接调用,相当于把堆里面的那个函数放在了另一个函数里单独调用,而并没有与该对象相关联,当该对象调用时也就是this指向了这个对象了。

function china(fn) {
    fn()
}
var chinese = {
    name: "赵文卓",
    kungfu: '踢飞刀',
    skill: function() {
        console.log(this.kungfu);
    }
}
china(chinese.skill)  //  undefined  不可能全中国的人都会踢飞刀
chinese.skill()     // 踢飞刀    但是赵文卓一定可以
复制代码

隐式绑定

  • 当函数引用有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。

  • 对象属性引用链中只有最后一层在调用位置中起作用。

  • 要求:对象内部必须包含一个指向函数的属性,该对象可通过这个属性间接引用函数。

function foo() {
    let name = '乾隆'
    console.log(this.name);
}
let obj2 = {
    name: '雍正',
    next: foo
}
let obj1 = {
    name: '康熙',
    next: obj2
}

obj1.next.next()  //  雍正   看到这里是不是以为康熙的下一任的下一任怎么不是乾隆,害,这里毕竟是代码。
复制代码

被调用的函数中的this会绑定到最靠近的那层的上下文对象。

  • 隐式丢失:指隐式绑定的函数丢失绑定对象,也就是说它会应用默认绑定,从而默认绑定到全局或者undefined。

var woman = '紫薇'
var emperor = {   //  皇帝
    woman: '夏雨荷',
    meet: function() {
        console.log(this.woman);
    }
}
var xyz = emperor.meet	//  这里xyz拿到了meet函数的引用,也就是meet函数本身,所以也就没了emperor的上下文了
xyz()  //  紫薇   这里独立函数调用  //  这里面的剧情自己可以理出来了(*^﹏^*) 
复制代码

回调函数里发生的隐式丢失,这里其实就是函数作为参数,然后再setTimeout函数里独立运行。

var woman = '紫薇'
var emperor = {   //  皇帝
    woman: '夏雨荷',
    meet: function() {
        console.log(this.woman);
    }
}
setTimeout(emperor.meet, 3000); //  紫薇  三秒后皇帝见到了紫薇
复制代码

显式绑定

  • 通过callapply,将this绑定到该对象。call和apply区别在于第二个参数不同,call是参数列表,apply是数组。

function getMoney() {
    console.log(this.card);
}
var wife = {
    card: 1000,
    getMoney: getMoney
}
var husband = {
    card: 999999
}
wife.getMoney()  //  1000
wife.getMoney.call(husband)  //  999999    双十一要到了,老婆准备去霍霍老公的卡。
复制代码

从这里也能看出显式绑定和隐式绑定的优先级:显式绑定>隐式绑定

new绑定

new关键字会进行如下的操作:

  1. 创建一个新的对象({});

  2. 为这个新的对象添加__proto__属性,将该属性指向构造函数的原型对象;

  3. 将新创建的对象作为this的上下文;

  4. 如果该函数没有返回对象,则返回this

function Father(y) {
    this.y = y;
}
var son = new Father('Y');	//  son这个新创建的对象作为了this的上下文,也就是构造函数里的this添加的属性都是往son里添加的
console.log(son.y);  //  Y   父亲的Y染色体决定了你是个son
复制代码

补充:箭头函数没有this,它所采用的是词法作用域 。

剧情讲完了,这里就来上一段快手的面试题吧。如何输出456?

var name = '123';
var obj = {
  name: '456',
   getName: function () {
      function printName() {
         console.log(this.name);
      }
      printName();
    }
}
obj.getName();  //  123
复制代码

既然讲到了箭头函数部分,想必你已经想到了要把某个函数改成箭头函数吧。还有种方法就是用到call了。

var name = '123';
var obj = {
  name: '456',
   getName: function () {
      let printName = () => {
         console.log(this.name);
      }
      printName();
    }  
}
obj.getName();  //  456
复制代码

此处getName函数中this的指向也就是定义时所在的对象,而非像前面那些运行时才绑定this。

优先级

上面显式绑定的例子已经对比出了显式绑定>隐式绑定,毫无疑问,默认绑定的优先级是最低 的,现在就来看看new绑定和隐式绑定吧。

function father(x) {
    this.x = x;
}

var daughter = {}
var wife = {
    x: 'X',
    father:father
}
//  丈夫是个变种人,由于长时间和丈夫待在一起,wife基因发生了突变
wife.father('Y')
console.log(wife.x);  // Y
//  call技术实在太强大了,强行生下一个女儿  // 显式 > 隐式
wife.father.call(daughter, 'X')
console.log(daughter.x);  //  X
//  没想到new也很强大,又喜提千金  //  new > 隐式
var daughter2 = new wife.father('X')
console.log(wife.x);  //  Y
console.log(daughter2.x); //  X
复制代码

这样一来就差new绑定和显式绑定谁更强了。

function control(money) {
    this.money = money
}

var husband = {}
//  妻子掌握了丈夫的微信余额
var wife = control.bind(husband)
//  妻子使丈夫余额有了500
wife(500)
console.log(husband.money);  // 500
//  儿子诞生,余额1000
var son = new wife(1000)
//  生了儿子降低生活费,营养费
wife(200)
console.log(husband.money);  //  200
console.log(son.money);  //  1000
复制代码

在上面的wife的this绑定的了husband的上下文,但是在new的过程中this被修改了,所以new>显式。但是在当再次通过wife去改变husband余额仍然有效,这难道说new 不比显式的优先级高。具体原理感兴趣的可以去《你不知道的JavaScript》上卷里面去了解。

猜你喜欢

转载自blog.csdn.net/weixin_42981560/article/details/127274863