class中this的一个问题

最近在看class中,首先代码如下:

class Logger {
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text);
  }
}

const logger = new Logger();
const { printName } = logger; 
printName(); // TypeError: Cannot read property 'print' of undefined

当实例化之后,this指向实例化的对象,因此printName()运行这个方法之后由于this指向logger,所以logger里面并没有print方法(print方法在原型中)。
但是问题来了,我将上面代码的最后一行改成这样:

logger.printName();

这不报错了,而且能正确显示。
请问printName()和logger.printName(),这两种写法的区别在哪里,为何后者就能够正确显示,printName()中的this指向不都是实例化logger吗?

阅读 2.9k
3 个回答

首先你知道class的本质其实就是原型链prototype
那么上述代码其实本质就是:


function Logger () {

}

Logger.prototype.printName = function(name = 'there') {  
  this.print(`Hello ${name}`);
};  

Logger.prototype.print = function(text) {  
  console.log(text);
};  

const logger = new Logger();
logger.printName();

可以看到方法printName方法是在原型链上的,this指向也是Logger()这个函数,在实体化后指向的是实体。
这里的this指向是一个新的对象!


而在你这里说的

const { printName } = logger; 

这是对象的解构,适用于这种:

let logger = {
    printName: function () {
        .....////代码块
    }
}

而这里的this指向的是window,上面两者的构造方式不同,性质不同,this指向也不同,你直接用es6的解构来解新对象的原型链方法,是不合理的

jsthis 是在运行时产生的(箭头函数除外 箭头还是的this是在定义时产生)
a.printName() printNamethis就是a
printName() this 就是window
不管中间怎么变 只要看最后调用那一步

如果你想这样用 可以参考vuex代码

//Store constructor
const store = this
const { dispatch, commit } = this
this.dispatch = function boundDispatch (type, payload) {
  return dispatch.call(store, type, payload)
}
this.commit = function boundCommit (type, payload, options) {
  return commit.call(store, type, payload, options)
}

改成这样

class Logger {
  constructor(){
    
    const {printName} = this;
    this.printName = printName.bind(this);
    
  }
  printName(name = 'there') {
    this.print(`Hello ${name}`);
  }

  print(text) {
    console.log(text);
  }
}

const logger = new Logger();
const { printName } = logger; 
printName();

直接调用 变成全局函数 this指向window

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题