2017-09-27 44 views
0

我正在使用Object.defineProperty向对象添加一些属性。当我添加到对象的属性时,它正常工作。但是当我将它添加到对象的原型时,我得到了too much recursion错误。将ownProperty对象添加到对象的原型时出错

var obj = {}; 
 
Object.defineProperty(obj.__proto__, 'key', { 
 
    enumerable: true, 
 
    get:() => {return key}, 
 
    set: (value) => { 
 
     if (typeof(value) == 'number'){ 
 
      key = 2*value; 
 
     } 
 
    } 
 
}); 
 
obj.key = 3; 
 
console.log(obj.key);

为什么不能在原型对象中添加这种方式?

+0

哪里是'key'界定? (它很重要) – dandavis

+0

@dandavis,它之前没有定义。我使用setter作为初始化。但即使我在原型中定义它,我也会得到同样的错误。 – TheChetan

+0

你不能在那里定义它,你需要一个封闭的私有变量名为key(如图所示) – dandavis

回答

2

这是因为通过在Object的原型上定义属性,每个对象都可以获得getter/setter。而且JS中的所有东西都是一个Object,所以这意味着window也将有一个key setter/getter。

在您的setter/getter函数中,您只需使用key。由于您没有明确定义key变量,因此将使用window上定义的变量。这是导致递归的原因。

你做obj.key = 3,它调用的设置器,window.key = 2*value,它调用设置器,它确实window.key = 2*value。等等,直到达到最大调用堆栈。

不要在原型上添加一些东西,除非您在每个实例上都需要它。

而且由于您使用的是箭头函数,因此没有this绑定到setter/getter调用,因此您无法知道与哪个实例对象进行交互。

取而代之的是不要扩展Object的原型使其成为你自己的原型,并设置/获得正确的变量/属性。

例如使用实际的构造函数,并将箭头函数更改为常规函数表达式。这将使得setter/getter可以获得对象的实例引用。然后,您需要一些方法来跟踪哪个键属于哪个实例。如果不需要隐藏这些变量,则可以简单地使用带前缀的命名属性,例如:this._key = 2*value;否则,如果您想保持它们私密,则可以使用WeakMap

function YourClass(){}; 
 

 
(function(){ 
 
    var keyMap = new WeakMap(); 
 
    Object.defineProperty(YourClass.prototype, 'key', { 
 
    enumerable: true, 
 
    get: function(){ 
 
     return keyMap.get(this); 
 
    }, 
 
    set: function(value){ 
 
     if(typeof(value) == "number"){ 
 
     keyMap.set(this,2*value); 
 
     } 
 
    } 
 
    }); 
 
})(); 
 
obj = new YourClass(); 
 
obj.key = 3; 
 
console.log(obj.key); 
 

 

 
function secondClass(){} 
 

 
//make secondClass inherit from YourClass 
 
secondClass.prototype = Object.create(
 
    YourClass.prototype, 
 
    { 
 
    "constructor": { 
 
    configurable: true, 
 
    enumerable: false, 
 
    writable: true, 
 
    value: secondClass 
 
    } 
 
}); 
 

 
var obj2 = new secondClass(); 
 
obj2.key = 16; 
 
console.log(obj2.key);

而且因为你似乎确定使用ES6你可以只使用其中有一组类/获取语法

class YourClass { 
 
    constructor(){ 
 
     this._key = null; 
 
    } 
 
    set key(value){ 
 
     this._key = 2*value; 
 
    } 
 
    get key(){ 
 
     return this._key; 
 
    } 
 
} 
 

 
class SecondClass extends YourClass { 
 
    constructor(){ 
 
    super(); 
 
    } 
 
} 
 

 
var obj = new SecondClass(); 
 
obj.key = 17; 
 
console.log(obj.key);

+0

我需要将它添加到所有将从这个继承的对象,它必须去原型。你可以给我一个工作的例子,说明如何将它添加到原型而不会导致这种递归? – TheChetan

+0

我想知道为什么全局变量导致递归问题,直到我注意到提及'window'。这真的是一个非常有趣的错误,并且不推荐初学者使用'prototype'(或非标准'__proto__')来处理这个问题的完美例子! –

+0

@TheChetan,看到更新的答案。首先展示了一些使用构造函数使用ES5继承的示例。第二种使用ES6类语法。 –