2014-02-04 3 views
0

Я пытаюсь установить перечислимое свойство с установщиком на прототипе объекта. Установка перечислимого свойства на прототипе объекта

function Foo(){} 
Object.defineProperty(Foo.prototype, 'tag', { 
    enumerable: true, configurable: true, 
    set: function(x){ 
     if(typeof(x) == "string") { 
      Object.defineProperty(this, 'tag', {value: x}); 
     } 
    } 
}); 
var bar = new Foo(); 

bar.tag = 7;  console.log(bar.tag); // undefined 
bar.tag = "baz"; console.log(bar.tag); // "baz" 

console.log(bar); // {} 
console.log(bar.propertyIsEnumerable('tag')); // false 

Все работает, как ожидалось, за исключением двух последних строки.
Я только что протестировал код в узле v0.10.25. Я не понимаю, почему тег свойства не перечислим.
Как обходной путь, я использую Object.defineProperty в конструкторе против this вместо Foo.prototype, но я хотел бы понять, почему объект в javascript не может наследовать от enuerable свойств.

ответ

0

Вы повторно присвойте тег в функции набора (затенение тег путем создания элемента на экземпляр Foo с именем бар), но не устанавливать его enumarable или конфигурируемый попробовать следующее:

function Foo(){} 
Object.defineProperty(Foo.prototype, 'tag', { 
    enumerable: true, configurable: true, 
    set: function(x){ 
     if(typeof(x) == "string") { 
      Object.defineProperty(this, 'tag', { 
       value: x, 
       enumerable: true 
      }); 
     } 
    } 
}); 
var bar = new Foo(); 

bar.tag = 7;  console.log(bar.tag); // undefined 
bar.tag = "baz"; console.log(bar.tag); // "baz" 

console.log(bar); // { tag="baz" } 
console.log(bar.propertyIsEnumerable('tag')); // true 

Более подробную информацию о затенение членов, функции конструктора и прототип: https://stackoverflow.com/a/16063711/1641941

-1

Я думаю, что вы можете определять свойства объекта, а не прототип или функцию конструктора, см. Также this post.

Вот почему положить object.defineProperty внутри конструктора будет работы: this внутри конструктора является объектом.

+1

Нет, прототип может быть установлен с чем угодно. Вы можете использовать defineProperty, defineProperties или Object.create, чтобы установить значение прототипа. – HMR

2

проблема заключается в том, что ваши два Object.defineProperty вызова определяет различные свойства:

  • Один сеттер свойство на прототипе
  • Одно значение свойства на каждом this, то есть экземпляр

В то время как один на прототипе перечисляемость и настраивается, то свойство экземпляра не будет «наследовать» эти дескрипторы; и они будут default to false на новом дескрипторе. Вам необходимо будет установить их в явном виде:

Object.defineProperty(Foo.prototype, 'tag', { 
    enumerable: true, configurable: true, 
    set: function(x){ 
     if (typeof(x) == "string") 
      Object.defineProperty(this, 'tag', { 
       enumerable:true, configurable:true, // still non-writable 
       value: x 
      }); 
    } 
}); 
+0

Привет, Берги, что-то странное случается, когда я устанавливаю вызывающий объект как Foo.prototype, а 'this' в setter ссылается на тот же элемент' tag': 'Foo.prototype.tag =" hello "; console.log (бар); // {tag = "hello"} console.log (bar.propertyIsEnumerable ('tag')); // false ", даже если enumerable false, в журнале" bar "отображается элемент 'tag' (в Firefox с FireBug). Я думаю, это потому, что у бара нет собственного свойства с именем tag: 'console.log (Foo.prototype.propertyIsEnumerable ('tag')); // = true' – HMR

+1

Я бы сказал, что вам нужно 'Object.getPrototypeOf (bar) .propertyIsEnumerable ('tag') // true', поскольку это работает только для * собственных * свойств, которые' bar' еще не имеют:) – Bergi

+0

yes, correct: 'console.log (bar.propertyIsEnumerable ('nonexisting')); // false' Я думаю, что 'propertyIsEnumerable' вернет false, если объект' hasOwnProperty' является ложным. Не удается найти ссылку, но, похоже, это так. – HMR

Смежные вопросы