【问题标题】:Javascript Objects - "this" is undefined?Javascript 对象 - “this”未定义?
【发布时间】:2017-08-20 21:11:02
【问题描述】:

我正在为更改计算器练习编写一些 Javascript。要求之一是使用对象构造函数;但是,我在从对象的一个​​方法中访问对象中的属性时遇到了很多麻烦。

这是我的对象:

function Coin(intValue){
    this.intCents = null; //The property

    function setCents(intValue) { //Trying access the intCents property from within this method

        /// <summary>Sets the intCents property for this object. If the given value is invalid, then the intCents property is given NaN.</summary>
        /// <param name="intCents" type="Number">The new intCents value.</param>
        if (isValid(intValue)) {
            this.intCents = intValue; //---javascript bugs out here!---
        } else {
            console.error("Invalid value given to Coin Object.");
            this.intCents = NaN;
        }
    }

    setCents(intValue);

    function getCents() {
        /// <summary>Returns the value of intCents.</summary>
        /// <returns type="Number">The intCents value.</returns>
        return this.intCents;
    }
}

这是我使用对象的方式:

var objCoin;

var calculateChange = function () {
    if (objCoin != null) {
        objCoin.setCents(Number.parseInt("67"));
    } else {
        objCoin = new Coin(Number.parseInt("67"));
    }
}

我去掉了一些不必要的代码,但总体来说基本功能如下: 用户在文本框中输入一个数字,然后单击网页上的按钮。按钮通过onclick事件调用calculateChange方法。

在“67”所在的 calculateChange 方法中,通常会有一些代码来获取文本框的值。为了简化代码并提供一个具体示例来说明传入的值类型,我将其替换为“67”。

假设用户输入一个整数...

如果我的 objCoin 变量没有用 Coin 实例实例化,则创建一个新实例并通过 Coin 的构造函数传入用户的输入。如果我的 objCoin 被实例化,那么使用 setCents 方法来保存用户的输入。

这是一个屏幕截图,显示了正在发生的事情以及 javascript 错误的位置:

据我了解,问题似乎与“this”关键字有关,因为它在 if 语句中显然未定义。尽管如此,我认为我的代码没有任何问题。

根据我在课堂上的理解,this.intCents = null; 是为 Coin 对象创建属性的正确方法,this.intCents 将是从对象中引用该属性的正确方法,而不管具体在哪里它是对象。

我尝试阅读以下问题:

'this' is undefined in JavaScript class methods 似乎更多地谈论 new 关键字和访问已创建对象的属性。

How does the "this" keyword work? 有很多有趣的例子;但是,我仍然没有看到我的代码中的缺陷。

访问intCents 属性时哪里出错了?

在这种情况下this 是什么? (我相信是对象变量 objCoin)

使用的程序:

Visual Studio 2015 企业版

谷歌浏览器及其开发者工具

【问题讨论】:

  • 使用箭头函数,将其保存到外部变量,使函数成为实例方法等
  • 我可以问一下为什么我被否决了吗? ...
  • 这不可能是你完整的Coin() 函数,否则objCoin.setCents(...) 会抛出一个错误,因为它不会被定义。
  • 关于setCents(intCents),这实际上是我在尝试修复代码时犯的错字。错字已修正。
  • @Tyler 这不是我要说的。在您的代码中,您没有将function setCents() {...} 附加到this,因此在脚本退出构造函数后,它将与function getCents() {...} 一起被垃圾收集。

标签: javascript this


【解决方案1】:

您需要将函数定义为您创建的对象的属性,如下所示:

function Coin(intValue){
    this.intCents = null; //The property

    this.setCents = function(intValue) { //Trying access the intCents property from within this method

        /// <summary>Sets the intCents property for this object. If the given value is invalid, then the intCents property is given NaN.</summary>
        /// <param name="intCents" type="Number">The new intCents value.</param>
        if (isValid(intValue)) {
            this.intCents = intValue; //---javascript bugs out here!---
        } else {
            console.error("Invalid value given to Coin Object.");
            this.intCents = NaN;
        }
    }

    this.setCents(intCents);

    this.getCents = function() {
        /// <summary>Returns the value of intCents.</summary>
        /// <returns type="Number">The intCents value.</returns>
        return this.intCents;
    }
}

更好:将它应用到构造函数的原型中:

function Coin(intValue){
    this.intCents = null; //The property
    this.setCents(intCents);

}

Coin.prototype.setCents = function(intValue) { //Trying access the intCents property from within this method

        /// <summary>Sets the intCents property for this object. If the given value is invalid, then the intCents property is given NaN.</summary>
        /// <param name="intCents" type="Number">The new intCents value.</param>
        if (isValid(intValue)) {
            this.intCents = intValue; //---javascript bugs out here!---
        } else {
            console.error("Invalid value given to Coin Object.");
            this.intCents = NaN;
        }
    }

    Coin.prototype.getCents = function() {
        /// <summary>Returns the value of intCents.</summary>
        /// <returns type="Number">The intCents value.</returns>
        return this.intCents;
    }

您所做的是:您创建了一个 named 函数(这与创建变量相似,但不完全相同)。此定义发生在构造函数中,因此其“可见性”仅限于该函数的范围。这种行为实际上用于模拟 private 属性或方法(即使在 ES6 中,内部也是如此)。所以难怪从外部无法访问该功能。

现在到“this 关键字的工作原理”部分:

this 总是访问被绑定 到该关键字的对象的属性。您可以使用function.bind 方法将任何对象绑定到函数,在该函数内部,this 绑定到该对象。此外,您可以使用function.bind 将函数应用到特定对象,但通常,当您使用new 关键字时,您可以这样做:

var x = new Coin( 3 );

new 创建一个对象并将函数Coin 应用于它。该新对象稍后将被分配给名为 x 的变量(后面的意思是:在构造函数完成执行之后)。

在构造函数中,您可以使用this 访问该新对象。当您想创建一个函数作为该对象的方法时,您需要将其分配给如下属性:

this.methodName = function( param ){ ... };

通过这样做,您将一个闭包(匿名函数)分配给一个属性,这使它成为一个方法。

这允许您稍后在构造函数创建的任何对象上调用该方法:

x.methodName( paramValue );

每个对象都有一个所谓的原型对象。这通常只是查找方法和属性的“后备”:如果在您的对象 itelf 上找不到您尝试访问的方法或属性,则正在搜索其原型对象以查找该标识符。这个对象也有一个原型,所以查找一直持续到最上面的父对象被搜索到为止。如果仍未找到该属性,则为undefined。

每个function 都有一个名为prototype 的属性:这不是函数本身的原型对象,而是分配给此(构造函数)创建的每个对象的原型对象(使用new) .因此,通过将这些函数作为属性分配给构造函数原型,您不需要一次又一次地为每个创建的对象添加相同的方法(这意味着,每个创建的 Coin-object 都会有自己的 getCents-Method => 内存密集型),但您只定义了一次方法,将它分配给原型对象,该对象对于使用new Coin( n ) 创建的每个Coin-对象相同(只要您不这样做) t 更改原型对象,出于优化原因,您不应该这样做)。

【讨论】:

  • this.setCents(intCents),也请说明原因。
  • 就我的理解而言,原型的目的是在对象需要额外功能时为其添加新事物。如果我知道对象首先需要 setCents 和 getCents,为什么还要使用原型?
  • 我也会在回答中解释原型链
  • 感谢原型链上的澄清,这就是我在调试中所缺少的。 :)
【解决方案2】:

这可能是How does the “this” keyword work?的副本

函数的 this 通常由调用设置(bind 和箭头函数是例外,但它们在这里无关)并且作用域为当前执行上下文(箭头函数除外,它采用其直接外部上下文的 this)。

所以给定构造函数中的setCents函数被调用而不设置它的this:

function setCents(intValue) {
    if (isValid(intValue)) {
        this.intCents = intValue; //---javascript bugs out here!---
    } else {
        console.error("Invalid value given to Coin Object.");
        this.intCents = NaN;
    }
}

setCents(intValue);

然后它的 this 将默认为全局对象(或在严格模式下保持未定义)。它不会是新实例。

getCents 和 setCents 方法无法从构造函数外部访问,因此它们很可能应该位于构造函数的原型上,因此它们被每个实例继承,例如

function Coin(intValue) {
  this.intCents = null; //The property
  // Initialise cents
  this.setCents(intValue);
}

Coin.prototype.setCents = function(intValue) {
    // isValid not provided so commented out
//  if (isValid(intValue)) {
    this.intCents = intValue; 
//    } else {
//    console.error("Invalid value given to Coin Object.");
//    this.intCents = NaN;
//  }
}

Coin.prototype.getCents = function() {
  return this.intCents;
}

var aCoin = new Coin(25);
console.log(aCoin.getCents()) // 25
aCoin.setCents(50);
console.log(aCoin.getCents()) // 50

【讨论】:

  • 随着 Psi 的回答,我误解了自己的原型概念。感谢您的澄清!
  • @Tyler——新的(ish)class syntax 让事情变得更加整洁,但不幸的是仍有许多不支持它的常用浏览器(例如任何版本的 IE 和 Opera) .您还可以使用 get 和 set,这也有帮助。
  • 是的,语法看起来更整洁。我可能很快就会在我的大学课程中看到它,我们最近才开始研究 javascript 类和对象。
  • 然而,类语法只是语法糖。新的 ES6 语法结构的一切可能都可以用 ES5 完成。例如,您可以使用 Object.defineProperty 在 ES5 中定义 getter 和 setter
猜你喜欢
  • 1970-01-01
  • 2017-05-26
  • 2013-01-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-14
  • 1970-01-01
相关资源
最近更新 更多