JavaScript: почему метод Object.hasOwnProperty ведет себя так?
Я понимаю, что Object.hasOwnProperty
Метод проверяет, имеет ли объект собственное имя свойства, что означает не наследуемое свойство. Это будет означать, что функция должна возвращать false, когда свойство a. не существует, или б. если это унаследовано.
Поправьте меня, если я ошибаюсь, но если это не использует классическое наследование, не делает bar
наследовать от Foo
в коде ниже? Почему hasOwnProperty
метод, возвращающий истину, когда propname
собственность является наследственной собственностью? Что я тут не так понял?
Кроме того, как бы я использовал hasOwnProperty
на Foo
объект? Код здесь возвращается false
при проверке Foo
объект.
function Foo() {
this.propname = 'test';
}
var bar = new Foo();
console.log(bar.hasOwnProperty('propname')); // returns true
console.log(Foo.hasOwnProperty('propname')); // returns false
5 ответов
Исходный пример кода эквивалентен:
function Foo() {
}
var bar = new Foo();
bar.propname = 'test';
console.log(bar.hasOwnProperty('propname')); // returns true
console.log(Foo.hasOwnProperty('propname')); // returns false
Вот почему bar.hasOwnProperty('propname')
возвращает true (свойство было явно установлено для объекта bar), и Foo.hasOwnProperty('propname')
возвращает false (свойство не было установлено для Foo вообще, ни для самого объекта Foo, ни для прототипа).
hasOwnProperty
проверка обычно используется так:
function Foo() {
this.propname = 'test';
}
Foo.prototype.inheritedprop = 'test';
var bar = new Foo();
console.log(bar.hasOwnProperty('propname')); // returns true
console.log(bar.hasOwnProperty('inheritedprop')); // returns false
Камнем преткновения здесь является то, что Javascript использует прототип наследования. То, что вы видите, на самом деле вовсе не наследование.
hasOwnProperty
вернусь false
если свойство:
- Не существует.
- Существует, но только в цепи прототипа.
Класс в вашем коде не имеет ничего общего с наследованием, это просто функция, которая устанавливает некоторые свойства объекта.
Этот объект является экземпляром нового пустого объекта, потому что вы вызвали функцию с new
Ключевое слово, которое, вероятно, откуда исходит путаница.
Представьте, что переписываете функцию так:
function foo() {
var bar = {};
bar.propname = 'test';
return bar;
}
var baz = foo();
Вы ожидаете baz.hasOwnProperty('propname')
вернуть истину? Абсолютно потому, что мы явно определили свойство объекта.
Альтернативный способ объявить собственность состоял бы в том, чтобы объявить это на Foo
прототип.
function Foo() {
this.bar = 'baz';
}
Foo.prototype.propname = 'test';
var baz = new Foo();
baz.propname; // 'test'
baz.hasOwnProperty('propname'); // false
Опять же, магические вещи, происходящие здесь, все вплоть до new
ключевое слово. Когда вы вызываете функцию с new
функция присваивает значение this
быть новым объектом и устанавливает прототип этого объекта таким же, как прототип функции, которую вы вызываете.
Может быть, самый простой способ объяснить это, что есть hasOwnProperty
метод на bar
, но если вы позвоните bar.hasOwnProperty('hasOwnProperty')
это вернется false
,
Это потому что hasOwnProperty
Метод живет на самом верху цепочки прототипов, на Object.prototype
, Каждый объект в Javascript наследуется отсюда, поэтому каждый объект будет иметь hasOwnProperty
метод.
Есть хорошая статья о том, почему new
делает объектно-ориентированное программирование трудным в Javascript.
Нет, propname
на самом деле установлен на примере Foo
который создан new
на основе Foo.prototype
(то есть this
). Другое приближение шаблона конструктора проясняет (э), что происходит:
var FooPrototype = {};
var bar = Object.create(FooPrototype);
bar.propname = "test";
Сначала вы должны создать новый объект класса Foo.
Эта корзина JS дополнительно иллюстрирует этот момент: http://jsbin.com/zaredowive/2/edit?js,console,output
Как вы можете видеть, конструктор вызывается только тогда, когда вы создаете новый объект класса Foo, который в этом случае является переменной с именем bar. Вы вызываете hasOwnProperty для функции Foo. Эта функция не содержит свойств.
Когда вы впервые написали Foo, вы просто определили функцию, которая будет использоваться позже.
"Бар" создает эту функцию и, по сути, активирует все, что находится внутри нее.
Проверьте эту скрипку с этими console.logs
console.log(Foo)
console.log(bar)