Поиск…
Стандартный прототип функции
Начните с определения функции Foo
которую мы будем использовать в качестве конструктора.
function Foo (){}
Редактируя Foo.prototype
, мы можем определить свойства и методы, которые будут использоваться всеми экземплярами Foo
.
Foo.prototype.bar = function() {
return 'I am bar';
};
Затем мы можем создать экземпляр с использованием new
ключевого слова и вызвать метод.
var foo = new Foo();
console.log(foo.bar()); // logs `I am bar`
Разница между Object.key и Object.prototype.key
В отличие от языков, таких как Python, статические свойства функции конструктора не наследуются экземплярами. Экземпляры только наследуют от своего прототипа, который наследуется от прототипа родительского типа. Статические свойства никогда не наследуются.
function Foo() {};
Foo.style = 'bold';
var foo = new Foo();
console.log(Foo.style); // 'bold'
console.log(foo.style); // undefined
Foo.prototype.style = 'italic';
console.log(Foo.style); // 'bold'
console.log(foo.style); // 'italic'
Новый объект из прототипа
В JavaScript любой объект может быть прототипом другого. Когда объект создается как прототип другого, он наследует все свойства своего родителя.
var proto = { foo: "foo", bar: () => this.foo };
var obj = Object.create(proto);
console.log(obj.foo);
console.log(obj.bar());
Консольный выход:
> "foo"
> "foo"
ПРИМЕЧАНИЕ. Object.create
доступен из ECMAScript 5, но вот полиполк, если вам нужна поддержка ECMAScript 3
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
Object.create ()
Метод Object.create () создает новый объект с указанным объектом и свойствами прототипа.
Синтаксис: Object.create(proto[, propertiesObject])
Параметры :
- proto (Объект, который должен быть прототипом вновь созданного объекта.)
- propertiesObject (Необязательно. Если задано и не определено, объект, чьи перечисляемые собственные свойства (то есть те свойства, которые определены сами по себе, а не перечислимые свойства вдоль его цепи прототипов), определяют дескрипторы свойств, которые должны быть добавлены к вновь созданному объекту, с соответствующим имена свойств. Эти свойства соответствуют второму аргументу Object.defineProperties ().)
Возвращаемое значение
Новый объект с указанным объектом и свойствами прототипа.
Исключения
Исключение TypeError, если параметр proto не равен null или объекту.
Прототипное наследование
Предположим, что у нас есть простой объект, называемый prototype
:
var prototype = { foo: 'foo', bar: function () { return this.foo; } };
Теперь нам нужен еще один объект, называемый obj
который наследуется от prototype
, что является тем же самым утверждением, что prototype
является прототипом obj
var obj = Object.create(prototype);
Теперь все свойства и методы из prototype
будут доступны для obj
console.log(obj.foo);
console.log(obj.bar());
Консольный выход
"foo"
"foo"
Прототипное наследование производится через ссылки на объекты внутри, а объекты полностью изменяемы. Это означает, что любое изменение, которое вы делаете на прототипе, немедленно повлияет на все другие объекты, прототип которых является прототипом.
prototype.foo = "bar";
console.log(obj.foo);
Консольный выход
"bar"
Object.prototype
является прототипом каждого объекта, поэтому настоятельно рекомендуется вам не возиться с ним, особенно если вы используете какую-либо стороннюю библиотеку, но мы можем немного поиграть с ним.
Object.prototype.breakingLibraries = 'foo';
console.log(obj.breakingLibraries);
console.log(prototype.breakingLibraries);
Консольный выход
"foo"
"foo"
Интересный факт Я использовал консоль браузера, чтобы сделать эти примеры и сломал эту страницу, добавив свойство breakingLibraries
.
Псевдоклассическое наследование
Это эмуляция классического наследования, использующая прототипическое наследование, которое показывает, насколько мощными прототипами. Это было сделано, чтобы сделать язык более привлекательным для программистов, поступающих с других языков.
ВАЖНОЕ ПРИМЕЧАНИЕ . Поскольку ES6 не имеет смысла использовать псевдокальсическое наследование, так как язык имитирует обычные классы . Если вы не используете ES6, вы должны . Если вы все еще хотите использовать классический шаблон наследования, и вы находитесь в среде ECMAScript 5 или ниже, то ваш псевдо-классический вариант - ваш лучший выбор.
«Класс» - это просто функция, которая вызывается с new
операндом и используется как конструктор.
function Foo(id, name) {
this.id = id;
this.name = name;
}
var foo = new Foo(1, 'foo');
console.log(foo.id);
Консольный выход
1
foo - это экземпляр Foo. Соглашение о кодировании JavaScript говорит, что если функция начинается с случая с большой буквы, она может быть вызвана как конструктор (с new
операндом).
Чтобы добавить свойства или методы в «класс», вы должны добавить их в свой прототип, который можно найти в свойстве prototype
конструктора.
Foo.prototype.bar = 'bar';
console.log(foo.bar);
Консольный выход
бар
Фактически то, что Foo делает как «конструктор», просто создает объекты с Foo.prototype
качестве прототипа.
Вы можете найти ссылку на свой конструктор на каждом объекте
console.log(foo.constructor);
функция Foo (id, name) {...
console.log({ }.constructor);
function Object () {[native code]}
А также проверьте, является ли объект экземпляром данного класса с оператором instanceof
console.log(foo instanceof Foo);
правда
console.log(foo instaceof Object);
правда
Настройка прототипа объекта
С помощью ES5 + функция Object.create
может использоваться для создания объекта с любым другим объектом в качестве прототипа.
const anyObj = {
hello() {
console.log(`this.foo is ${this.foo}`);
},
};
let objWithProto = Object.create(anyObj);
objWithProto.foo = 'bar';
objWithProto.hello(); // "this.foo is bar"
Чтобы явно создать объект без прототипа, используйте null
в качестве прототипа. Это означает, что объект не будет наследовать от Object.prototype
и полезен для объектов, используемых для проверки сущностей существования, например
let objInheritingObject = {};
let objInheritingNull = Object.create(null);
'toString' in objInheritingObject; // true
'toString' in objInheritingNull ; // false
Из ES6 прототип существующего объекта можно изменить, используя Object.setPrototypeOf
, например
let obj = Object.create({foo: 'foo'});
obj = Object.setPrototypeOf(obj, {bar: 'bar'});
obj.foo; // undefined
obj.bar; // "bar"
Это можно сделать практически в любом месте, в том числе на this
объекте или в конструкторе.
Примечание. Этот процесс очень медленный в текущих браузерах и должен использоваться экономно, попробуйте вместо этого создать объект с нужным прототипом.
До ES5 единственным способом создания объекта с помощью заданного вручную прототипа было создание его с помощью new
, например
var proto = {fizz: 'buzz'};
function ConstructMyObj() {}
ConstructMyObj.prototype = proto;
var objWithProto = new ConstructMyObj();
objWithProto.fizz; // "buzz"
Это поведение достаточно близко к Object.create
что можно написать полипол.