#javascript
#javascript
Вопрос:
У меня есть этот конструктор объектной функции:
const Shape = function(name){
this.name = name;
}
Shape.prototype.getName = function(){
return this.name;
};
и у меня есть этот экземпляр
const square = new Shape("square");
Когда я использую цикл for для итерации по квадратному объекту, я вижу, что процесс итерации выполняется над прототипом квадратного объекта
for (const key in square) console.log(key);
/* #output:
name
getName
*/
но когда я использую функцию Object.keys(), я вижу, что процесс итерации не повторяется по объекту-прототипу
/* #output:
["name"]
*/
В чем причина этого за кулисами?
Вот что я пробовал:
Я пытался утешить.зарегистрируйте дескриптор метода getName из объекта-прототипа, я видел, что для атрибута enumerable по умолчанию установлено значение true:
console.log(Object.getOwnPropertyDescriptor(Object.getPrototypeOf(square), "getName"))
/* #output:
configurable: true
enumerable: true
value: ƒ ()
writable: true
__proto__: Object
*/
Ответ №1:
Object.keys
выполняет итерацию только по перечислимым собственным свойствам. Напротив, for..in
выполняет итерацию по всем перечисляемым свойствам в любом месте цепочки прототипов объекта.
С этим кодом:
const Shape = function(name){
this.name = name;
}
Shape.prototype.getName = function(){
return this.name;
};
Shape
Экземпляр получает собственное свойство a name
, поэтому он повторяется обоими итерационными методами. Напротив, getName
находится в прототипе экземпляра — это не свойство самого экземпляра, поэтому оно не возвращается в Object.keys
:
const Shape = function(name){
this.name = name;
}
Shape.prototype.getName = function(){
return this.name;
};
const square = new Shape("square");
console.log(
square.hasOwnProperty('name'),
square.hasOwnProperty('getName'),
Shape.prototype.hasOwnProperty('getName')
);
Ответ №2:
В чем причина этого за кулисами?
for-in
перебирает все перечислимые свойства объекта со строковыми именами, включая унаследованные.
Object.keys
предоставляет вам только массив собственных (не унаследованных) свойств объекта с перечислимыми строковыми именами. Просто для иллюстрации, это похоже на:
// Rough, not-exact-in-every-detail implementation of `Object.keys`
// in terms of `for-in`
const result = [];
for (const name in object) {
if (Object.prototype.hasOwnProperty.call(object, name)) {
result.push(name);
}
}
Также есть Object.getOwnPropertyNames
который предоставляет вам массив всех собственных свойств объектов с именами строк (даже неисчислимых) и Object.getOwnPropertySymbols
который предоставляет вам массив собственных свойств объекта с именами символов (даже неисчислимых). (Нет символа, эквивалентного Object.keys
.)
Я пытался утешить.зарегистрируйте дескриптор метода getName из объекта-прототипа, я видел, что для атрибута enumerable по умолчанию установлено значение true:
Это когда вы создаете свойство с помощью присваивания, как вы делаете в своем вопросе. Если вы создаете свойство с помощью Object.defineProperty
или с помощью синтаксиса метода в class
конструкции, по enumerable
умолчанию используется значение false
.
Примеры:
// Your original code:
const Shape = function(name){
this.name = name;
}
Shape.prototype.getName = function(){
return this.name;
};
showFlag(Shape.prototype, "getName"); // true
// Using `Object.defineProperty`:
const Shape2 = function(name){
this.name = name;
}
Object.defineProperty(Shape2.prototype, "getName", {
value: function(){
return this.name;
},
writable: true, // These also default to `false`, but you
configurable: true // usually want them to be `true` for methods
});
showFlag(Shape2.prototype, "getName"); // false
// Using `class` syntax
class Shape3 {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
showFlag(Shape3.prototype, "getName"); // false
function showFlag(proto, name) {
console.log(Object.getOwnPropertyDescriptor(proto, name).enumerable);
}