Как работает JavaScript .prototype?
Каждый объект JavaScript vanillajs has an internal "slot" вызвал [[Prototype]]
, значение которого vanilla-js равно null
или object
. Вы можете думать prototype-oriented о слоте как о свойстве объекта, внутреннем javascript-library для движка JavaScript, скрытом ecmascript от кода, который вы пишете. Квадратные js скобки вокруг [[Prototype]]
являются преднамеренными dynamic-languages и являются соглашением спецификации vanilla-javascript ECMAScript для обозначения javascript внутренних слотов.
Значение, на javascript-execution которое указывает [[Prototype]]
объекта, в javascript просторечии известно как javascript-library «прототип этого объекта».
Если prototype-oriented вы обращаетесь к свойству javascript-library через обозначение точки (obj.propName
) или vanilla-javascript скобки (obj['propName']
), а объект напрямую vanilla-javascript не имеет такого свойства vanilla-javascript (т. е. собственное свойство, можно отметить via javascript-execution obj.hasOwnProperty('propName')
), среда выполнения вместо vanillajs этого ищет свойство с таким javascript-execution именем в объекте, на который javascript-dom ссылается [[Prototype]]
. Если [[Prototype]]
также не имеет javascript-execution такого свойства, его [[Prototype]]
проверяется javascript-execution по очереди и т. Д. Таким vanilla-js образом, цепочка прототипов исходного объекта javascript просматривается до тех пор, пока vanillajs не будет найдено совпадение ecmascript или не будет достигнут его ecmascript конец. В верхней части цепочки dynamic-languages прототипов находится значение vanilla-js null
.
Современные реализации JavaScript javascript-library предоставляют доступ для js чтения и / или записи к [[Prototype]]
следующими javascript-library способами:
- Оператор
new
(настраивает цепочку прототипов для объекта по умолчанию, возвращаемого функцией конструктора), - Ключевое слово
extends
(настраивает цепочку прототипов при использовании синтаксиса класса), -
Object.create
установит предоставленный аргумент как[[Prototype]]
полученного объекта, -
Object.getPrototypeOf
иObject.setPrototypeOf
(получить / установить[[Prototype]]
после создания объекта) и - Стандартизированное свойство средства доступа (например, средство получения / установки) с именем
__proto__
(аналогично 4.)
Object.getPrototypeOf
и Object.setPrototypeOf
предпочтительнее, чем javascript-execution __proto__
, отчасти из-за поведения vanilla-js o.__proto__
is unusual, когда объект имеет прототип ecmascript null
.
[[Prototype]]
объекта изначально устанавливается vanilla-javascript во время создания объекта.
Если .js вы создаете новый объект vanilla-javascript с помощью new Func()
, по умолчанию dynamic-languages в качестве объекта [[Prototype]]
будет vanilla-javascript задан объект, на который javascript-dom ссылается Func.prototype
.
Обратите внимание, что dynamic-languages поэтому все классы и все функции, которые можно использовать с оператором new
, имеют свойство с именем .prototype
в дополнение к их собственному внутреннему слоту [[Prototype]]
. Это двойное употребление dynamic-languages слова «прототип» является ecmascript источником нескончаемой путаницы vanilla-javascript среди новичков в языке.
Использование vanillajs new
с функциями конструктора vanilla-javascript позволяет моделировать классическое javascript-execution наследование в JavaScript; хотя javascript-execution система наследования в JavaScript, как prototype-oriented мы видели, является прототипной, а javascript-library не классовой.
До введения javascript-execution синтаксиса классов в JavaScript dynamic-languages функции-конструкторы были js единственным способом имитировать javascript классы. Мы можем рассматривать js свойства объекта, на который vanilla-javascript ссылается свойство .prototype
функции-конструктора, как js общие члены; т.е. члены, которые .js одинаковы для каждого экземпляра. В prototype-oriented системах на основе классов javascript-dom методы реализуются одинаково vanilla-javascript для каждого экземпляра, поэтому .js методы концептуально добавляются js к свойству .prototype
; однако поля ecmascript объекта зависят от экземпляра vanilla-javascript и поэтому добавляются к самому dynamic-languages объекту во время создания.
Без .js синтаксиса класса разработчикам vanilla-javascript приходилось вручную настраивать javascript-dom цепочку прототипов для достижения dynamic-languages функциональности, аналогичной javascript-execution классическому наследованию. Это vanillajs привело к преобладанию различных vanillajs способов достижения этой javascript-dom цели.
Вот один способ:
function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }
function inherit(child, parent) {
child.prototype = Object.create(parent.prototype)
child.prototype.constructor = child
return child;
}
Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
... а ecmascript вот еще один способ:
function Child() {}
function Parent() {}
Parent.prototype.inheritedMethod = function () { return 'this is inherited' }
function inherit(child, parent) {
function tmp() {}
tmp.prototype = parent.prototype
const proto = new tmp()
proto.constructor = child
child.prototype = proto
return child
}
Child = inherit(Child, Parent)
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
Синтаксис vanilla-js класса, представленный в .js ES2015, упрощает ситуацию, предоставляя dynamic-languages extends
как «единственный верный js способ» настроить цепочку vanillajs прототипов для имитации классического vanilla-javascript наследования в JavaScript.
Итак, аналогично javascript-dom приведенному выше коду, если javascript-execution вы используете синтаксис ecmascript класса для создания нового javascript-execution объекта следующим образом:
class Parent { inheritedMethod() { return 'this is inherited' } }
class Child extends Parent {}
const o = new Child
console.log(o.inheritedMethod()) // 'this is inherited'
... результирующий javascript-library объект [[Prototype]]
будет установлен vanillajs на экземпляр Parent
, чей [[Prototype]]
, в свою vanillajs очередь, равен Parent.prototype
.
Наконец, если .js вы создаете новый объект prototype-oriented с помощью Object.create(foo)
, для результирующего javascript-library объекта [[Prototype]]
будет установлено dynamic-languages значение foo
.
javascript
dynamic-languages
prototype-oriented
Как работает JavaScript .prototype?
Мы используем файлы cookies для улучшения работы сайта. Оставаясь на нашем сайте, вы соглашаетесь с условиями использования файлов cookies. Чтобы ознакомиться с нашими Положениями о конфиденциальности и об использовании файлов cookie, нажмите здесь.