2015-08-18 4 views
1

При добавлении нескольких объектов к объекту добавление их с помощью Object.defineProperties() обычно создает более чистый и читаемый код, чем добавление их по одному или в группы.Самостоятельные ссылки в Object.defineProperties()

Однако, если свойство ссылается на другое, Object.defineProperties() не может его обработать. Рассмотрим фиктивный пример:

var foo = {}; 
Object.defineProperties(foo, { 
    "one" : {value: 1, enumerable: true}, 
    "two" : {value: foo.one + 1, enumerable: true} 
}) 
console.log(foo); // { one: 1, two: NaN } 

var bar = {}; 
Object.defineProperties(bar,{ 
    "one" : {value: 1, enumerable: true} 
}); 
Object.defineProperties(bar,{ 
    "two" : {value: bar.one + 1, enumerable: true} 
}); 

console.log(bar); // { one: 1, two: 2 } 

Теперь, как ясно, что второе решение всегда работает. Тем не менее, можно было бы предположить, что первый мог работать также, как он кажется как сокращение для другого и предлагает последовательную обработку свойств в любом случае.

Я не нашел достоверной документации по этому вопросу.

Так вопросы:

  • Это намеренное ограничение или техническая сложность в фоновом режиме?
  • Задокументировано?
  • Является ли это конкретным поведением или стандартным поведением?

Редактировать: ответьте ясно, и посмотрите мои комментарии там. Это простая буквальная проблема (не проблема, скорее :), не связанная напрямую с Object.defineProperties().

+1

Цель. Вам понадобятся два отдельных вызова '.defineProperties'. 'one' не определен до того, как весь метод был выполнен. – Teemu

+1

См. Также [Самостоятельные ссылки в декларациях литералов объектов] (http://stackoverflow.com/q/4616202/1048572). Не существует 'foo.one' перед вызовом' Object.defineProperties'. – Bergi

ответ

4

Проблема не имеет особого отношения к Object.defineProperties(). Проблема связана с тем, что выражения инициализатора объекта — «объектные литералы» - это другой термин —. Инициализатор объекта равен выражению, и до его оценки объект, который он инициализирует, действительно не существует. Таким образом, в

Object.defineProperties(foo, { 
    "one" : {value: 1, enumerable: true}, 
    "two" : {value: foo.one + 1, enumerable: true} 
}); 

объект инициализатор Подвыражение является

{ 
    "one" : {value: 1, enumerable: true}, 
    "two" : {value: foo.one + 1, enumerable: true} 
} 

Это должно быть оценено перед вызовом Object.defineProperties() даже сделано. В момент, когда он оценивается, foo не имеет свойства, называемого «один»; даже если бы это было так, значение в точке, в которой оценивается инициализатор объекта, будет прежним значением, а не новым значением.

Это как раз то, как работают выражения инициализатора объекта. Невозможно напрямую обратиться к инициализированному объекту внутри выражения. Это означает, что даже в таком заявлении:

var foo = { 
    "one" : {value: 1, enumerable: true}, 
    "two" : {value: foo.one + 1, enumerable: true} 
}; 

у вас все еще есть та же проблема.

+0

Спасибо, я раньше использовал геттеры и забыл, что позже попробовал явные значения. Поэтому я не понял, что сначала будет оценено значение. Имеет смысл. КПП.Возвращаясь к getters, это работает как и ожидалось (как и ожидалось): 'var foo = {};' 'Object.defineProperties (foo, {' '" one ": {get: function() { return 1}, enumerable: true}, ' \t' "two": {get: function() {return this.one + 1}, enumerable: true} ' '}) ' ' console.log (foo. один, foo.two); // 1, 2' – balage

+0

@balage Да, это сработает, потому что 'this.one' не оценивается до некоторого времени после завершения объекта. – Pointy