JavaScript构造函数和原型对象

时间:2012-11-03 23:32:24

标签: javascript

我很好奇这里发生了什么。如您所见,我已经定义了一个名为range的构造函数来构建新的range对象。我通过它的原型扩展了range构造函数,添加了一个简单的includes方法。我已经创建了我的新对象并使用了p的变量。当我尝试将此方法用于range个对象时,一切都很顺利,并且按预期工作。问题是当我试着看p.prototype它告诉我它的类型是未定义的而p.prototype没有方法......嗯?

这里发生了什么? p如何成为对象且p.prototype不是?

    function range(from, to) {
        this.from = from;
        this.to = to;
    }


    range.prototype = {
        includes: function(x) { return this.from <= x && x <= this.to; },
    }

    var p = new range(1, 4);

    console.log(typeof p) //outputs object
    console.log(typeof p.prototype) //outputs undefined

    console.log(Object.getOwnPropertyNames(range.prototype)); //outputs includes
    console.log(Object.getOwnPropertyNames(p.prototype)); //throws error, p.prototype is not an object

4 个答案:

答案 0 :(得分:2)

  

问题是当我试着看p.prototype它告诉我它的类型未定义时

这是对的。您的range构造函数创建的对象没有prototype属性,但它们有一个基础原型(从prototype函数的range属性中提取)

让我们来看看new range()时会发生什么:

  1. JavaScript引擎会创建一个新的空白对象。
  2. JavaScript引擎将该对象的基础原型(不是prototype)指定为range.prototype引用的对象。 (在规范中,此属性 - 在代码中不能直接访问,但见下文 - 称为[[Proto]]。)
  3. JavaScript引擎调用rangethis引用新对象。
  4. 假设range没有返回不同的对象(它可以执行;这有点模糊),new range的结果是创建的新对象第1步。
  5. 稍后,当您使用this.includes时,会发生以下情况:

    1. 引擎查看实际对象以查看它是否具有includes属性。
    2. 由于它没有,引擎会查看[[Proto]]以查看 it 是否有一个。
    3. 既然如此,就会使用那个(如果没有,它会查看[[Proto]]的{​​{1}}等等。)
    4. 这里的关键是:

      1. 对象具有底层原型,无法通过对象本身的任何命名属性访问。 (事实上​​,过去我们无法找到 。现在,在ES5中,我们有Object.getPrototypeOf。)
      2. 通过[[Proto]]创建的对象从new SomeFunctionName属性获取原型,这是SomeFunctionName.prototype对象的完全正常属性(函数是JavaScript中的第一类对象)。

      3. 附注:您正在使用您的代码替换SomeFunctionName prototype range。一般来说,虽然它有效,但我会避免这种情况。相反,扩充 range.prototype引用的现有对象。 (为它添加属性,而不是替换它。)但这不是你问题的核心。

答案 1 :(得分:0)

我想你想要的是:

range.prototype.includes = function(x) { 
    return this.from <= x && x <= this.to; 
}

答案 2 :(得分:0)

您重新定义了原型对象,因此对原始对象的引用已经消失。试试这个:

range.prototype.includes = function(x) { 
    return this.from <= x && x <= this.to;
}

答案 3 :(得分:0)

Number.prototype.myRound = function (decimalPlaces) {
    var multiplier = Math.pow(10, decimalPlaces);

    return (Math.round(this * multiplier) / multiplier);
};