В JavaScript функция — это объект типа Function
, который содержит свойства и методы. Прототип (Prototype)
— атрибут объекта типа Function
.
Атрибут prototype
включается при определении функции, а его начальное значение — пустой объект. В JavaScript для функций не определен тип прототипа, поэтому прототип может быть любого типа.
Прототип используется для сохранения общих свойств и методов объекта . Свойства и методы прототипа не влияют на свойства и методы самой функции.
// Свойства типа функции -> свойства, которые есть у всех функций console.log(Function.prototype); //[Function] //Определение функции function fn() { console.log('это функция'); } //Значением прототипа по умолчанию является пустой объект console.log(fn.prototype); //fn {} // Функция содержит конструктор --> все ссылочные типы на самом деле являются конструкторами console.log(Number.prototype); //[Number: 0] console.log(Object.prototype);//{}
Вы можете получить прототип объекта двумя способами установки общих свойств и методов:
prototype
конструктораgetPrototype
метода объекта Object (obj).функция фн() { console.log('это функция'); } //Используем структуру синтаксиса атрибутов объекта доступа console.log(fn.prototype); //fn {} console.log(fn['prototype']);//fn {} //Тип объекта предоставляет метод getPrototypeOf() console.log(Object.getPrototypeOf(fn)); //[Функция]
Метод Object.getOwnPropertyDescriptors()
используется для получения дескрипторов всех собственных свойств объекта.
var result = Object.getOwnPropertyDescriptor(Object.prototype,'constructor'); console.log(result) //Результаты вывода следующие: //{ // значение: [Функция: Объект], // доступно для записи: правда, // перечисляемое: ложь, // настраивается: правда // }
constructor是在创建函数的时候自动添加的,指向构造函数本身
Вы можете установить свойства и методы прототипа следующими двумя способами:
Constructor.prototype.Attribute name = значение атрибута; Constructor.prototype.Method name = function(){};
Когда нам нужно добавить к прототипу много атрибутов, слишком сложно снова и снова писать
构造函数.prototype.属性名
. Мы можем напрямую изменить весьprototype
. Имя атрибута: значение атрибута, Имя метода: function(){}}
function foo() {}foo.prototype = { конструктор: фу, название: 'варенье', возраст: 18, адрес: 'Пекин'}var fn = new foo()console.log(fn.address) //Пекин
Каждый объект будет иметь метод isPrototypeOf()
, который используется для определения того, является ли объект прототип другого объекта.
Пример кода выглядит следующим образом: // Определить объект через инициализатор var obj = { название: 'джем' } //Определяем функцию-конструктор Hero() {} // Назначаем объект obj прототипу конструктора Hero Hero.prototype = obj; // Создать объект с помощью конструктора var Hero = new Hero(); // Метод isPrototypeOf() определяет, является ли указанный объект прототипом другого объекта var result = obj.isPrototypeOf(hero); console.log(result);//true
проверяет, что объект
obj
является прототипом объекта-hero
Далее мы используем фрагмент кода, чтобы расширить наше понимание цепочки прототипов:
Сценарий : Найти объекты на объекте obj. Шаги, выполняемые атрибутом адреса js: 1. Будет запущена операция получения. 2. Поиск атрибута в текущем объекте. 3. Если он не найден, в этот момент будет выполнен поиск в объекте цепочки прототипов (__proto__). 1. Поиск завершится. Если он не найден, он продолжит поиск по цепочке прототипов, пока не будет найден прототип верхнего уровня (что такое прототип верхнего уровня, временно неясно)
var obj = {. название: 'варенье', возраст: 19 } /* Требование: Найдите атрибут адреса объекта obj*/. // Цепочка прототипов ищется слой за слоем. Если она не найдена, поиск будет осуществляться до тех пор, пока не будет найден прототип верхнего уровня. obj.__proto__.__proto__ = {} obj.__proto__.__proto__.__proto__ = { адрес: «Пекин» } console.log(obj.address) // Пекин console.log(obj.__proto__.__proto__.__proto__) // { адрес: 'Пекин' }
Наконец найдите атрибут адреса
那么这里有一个问题,如果一直没有查到,会无穷尽的去查找吗?接下来我们就来了解一下
Как мы уже упоминали выше, мы не будем бесконечно искать по цепочке прототипов. Когда прототип верхнего уровня будет найден, будет возвращено undefined
, если он еще не найден.
Так что же такое прототип верхнего уровня?
Пример кода выглядит следующим образом:
var obj = { name: 'jam' }console.log(obj.__proto__) // {}console.log(obj.__proto__.__proto__) //
Прототип объекта obj с нулевым литералом:
{}
.{}
— это прототип верхнего уровня. Когда мы продолжаем печатать__proto__
вверх, возвращается нулевое значение, что доказывает, что предыдущий слой уже является прототипом верхнего уровня.
Следующий рисунок является дополнением к прототипу верхнего уровня. отсутствует в первом фрагменте кода:
顶层原型就是Object.prototype
3.1 Так где же находится конец цепочки прототипов? Например, есть ли у третьего объекта атрибут прототипа __proto__
?
var obj = {name:'jam'}obj.__proto__ = {}obj.__proto__.__proto__ = {}obj.__proto__.__proto__.__proto__ = {}console.log(obj.__proto__.__proto__.__proto__.__proto__) // {}
Мы обнаружили, что напечатанный выше результат представляет собой空对象{}
var obj = { название: 'варенье', возраст: 19 } console.log(obj.__proto__) // {} console.log(Object.prototype) // {} console.log(obj.__proto__ === Object.prototype) // true
Object является родительским классом для всех классов, поэтому obj.__proto__ на самом деле является Object.prototype,
console.log(obj.__proto__ === Object.prototype) // true
мы видим, что результат Object.prototype является прототипом верхнего уровня.
{}
3.2 Тогда мы можем спросить. : {}
Есть ли что-то особенное в прототипах?
console.log(obj.__proto__.__proto__.__proto__.__proto__.__proto__) // null;
Object.prototype
является пустой объект {}, он не пуст, но свойства внутри не перечисляемы. Например, давайте напечатаем constructor
свойство для просмотра <!-- Видно, что атрибут конструктора существует и он не пуст -->console.log(Object.prototype.constructor) // [Функция: Object] <!-- конструктор ссылается на Object -->
Object.prototype
с помощью метода Object.getOwnPropertyDescriptors()
. console.log(Object.getOwnPropertyDescriptors(Object.prototype)) //Как показано на длинном скриншоте ниже