繁体   English   中英

无法读取未定义的属性,运行时错误

[英]Cannot read property of Undefined, Runtime Error

我这里有以下代码:

class ColorPrinter {
    constructor(sourceFile, colors) {
      this.sourceFile = sourceFile 
      this.colors = colors
    }

    showColors() {
      this.colors.forEach(this.printColor);
    }

    printColor(colorObj) {
      console.log(this.sourceFile, colorObj.name, colorObj.hex);
    }
  } 


const colors = [{name: "red", hex: "#FF0000"}, {name: "yellow", hex: "#FFFF00"}, {name: "cyan", hex: "#0000FF"}];
const cp = new ColorPrinter('colors.csv', colors);
cp.showColors();

但是,当我运行它时,我得到以下运行时错误:

“类型错误:无法读取未定义的属性‘sourceFile’”

我不明白为什么 JS 不高兴。 我不是试图从文件中读取,但它不会将字符串作为参数。

将其更改为:

this.colors.forEach((x) => this.printColor(x));

您的原始代码没有按预期工作的原因与作用域在 javascript 中的工作方式有关,特别是this的值是如何绑定的。

要理解的主要事情是(通常)当您调用一个函数时, this设置为调用该方法的对象

wookie.eatBanana(); // inside the eatBanana method, this === wookie

但是,如果您与对象分开调用该方法, this最终会是undefined

const detachedFn = wookie.eatBanana;

// same function, but now this === undefined
detachedFn(); 

当您将this.printColor传递给forEach时,您正在做的是传递函数本身,最终会被调用而不会绑定到您的对象:

const detachedFn = this.printColor;
this.colors.forEach((x) => detachedFn(x)); // this === undefined inside detachedFn, because it's invoked standalone

forEach实现中,它只是调用给定的函数。 有效地:

// pseudocode
function forEach(fn) {
  fn(); // no reference to your class instance; fn is just a regular function.
}

定义一个调用this.printColor()的新函数保留范围:

this.colors.forEach((x) => this.printColor(x));

function forEach(fn) {
  fn(); // inside this function your method is called *on your object*, preserving the 'this' binding.
}

箭头函数自动绑定到父作用域

箭头函数没有自己的 this。 使用封闭词法范围的 this 值; 箭头函数遵循正常的变量查找规则。 因此,在搜索当前作用域中不存在的 this 时,箭头函数最终会从其封闭的作用域中找到 this。

如果您首先将方法声明为箭头函数,箭头函数自动绑定也可以派上用场来解决这些问题。 (这是实验性的,可能需要 babel 类属性插件)。

// declaring this method as an arrow function causes it to bind to
// the parent scope (the class instance) which means you can invoke
// it independently of the instance.

printColor = (colorObj) => {
  console.log(this.sourceFile, colorObj.name, colorObj.hex);
}

// now this is fine because printColor is already bound to 'this'
this.colors.forEach(this.printColor);

或者,正如 palasн指出的那样,显式调用bind

// make a copy of printColor that's explicitly bound to 'this'.
const explicitlyBoundFn = this.printColor.bind(this);

// works
this.colors.forEach(explicitlyBoundFn);

您也可以通过callapply完成此操作,这两者都允许您传入范围(尽管在这种情况下没有理由这样做)。

// no reason to do this, but it works.
const detachedFn = this.printColor;
this.colors.forEach((x) => detachedFn.call(this, x));

希望这可以帮助。 如果有任何需要澄清的地方,很高兴更新它。

您也可以像这样绑定当前的this

this.colors.forEach(this.printColor.bind(this));

 class ColorPrinter { constructor(sourceFile, colors) { this.sourceFile = sourceFile this.colors = colors } showColors() { this.colors.forEach(this.printColor.bind(this)); } printColor(colorObj) { console.log(this.sourceFile, colorObj.name, colorObj.hex); } } const colors = [{name: "red", hex: "#FF0000"}, {name: "yellow", hex: "#FFFF00"}, {name: "cyan", hex: "#0000FF"}]; const cp = new ColorPrinter('colors.csv', colors); cp.showColors();

bind()方法创建一个新函数,在调用this函数时,将其this关键字设置为提供的值,并在调用新函数时在任何提供的参数之前提供给定的参数序列。

因此,如果没有在printColor方法中使用bind this是未定义的,通过使用bind我们只是告诉printColor方法this应该引用ColorPrinter类,以便我们可以访问this.sourceFile

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM