Углубленный анализ трудностей в прототипе

внешний интерфейс JavaScript

Эта статья синхронно распространяется в моемGithubначальство

Эта статья не будет слишком углубляться в основы, а вместо этого сосредоточится на трудностях прототипирования.

Вы можете сначала внимательно проанализировать картинку, а потом давайте вводить тему

prototype

Сначала давайте представимprototypeАтрибуты. Это явное свойство прототипа, которое есть только у функций. В основном все функции имеют это свойство, но есть одно исключение

let fun = Function.prototype.bind()

Если вы создадите функцию вышеописанным способом, вы обнаружите, что эта функция не имеетprototypeатрибут.

Как создается прототип

Это свойство создается автоматически, когда мы объявляем функцию.

function Foo() {}

И значением этого свойства является объект (он же прототип) только с одним свойствомconstructor

constructorСоответствует конструктору, т.е.Foo.

constructor

constructorЭто общественное свойство и не может быть перечислена. Как только мы изменили функциюprototype, то новый объект не имеет этого свойства (конечно его можно получить через цепочку прототиповconstructor).

Тогда у вас должен возникнуть вопрос, какая польза от этого атрибута? На самом деле это свойство можно назвать исторической проблемой, которая в большинстве случаев бесполезна.В моем понимании, я думаю, что оно имеет две функции:

  • Сообщите объекту экземпляра, какая функция его построила
  • Если вы хотите добавить некоторые пользовательские методы в конструкторы в некоторых библиотеках классов, вы можете передатьxx.constructor.methodрасширять

_proto_

Это неявно в каждом объекте имеет свойство прототипа, указывая на создание прототипа конструктора объекта. На самом деле этот атрибут указывает на [[прототип]], но [[прототип]] внутреннее свойство, у нас не было доступа к, поэтому использовать_proto_посещать.

Поскольку в JS нет понятия класса, для достижения аналогичного наследования через_proto_Соединение объектов и прототипов в цепочку прототипов позволяет объектам получать доступ к свойствам, которые им не принадлежат.

экземпляр объекта_proto_как производить

Как видно из приведенного выше рисунка, когда мы используемnewоператор, результирующий экземпляр объекта имеет_proto_Атрибуты.

function Foo() {}
// 这个函数是 Function 的实例对象
// function 就是一个语法糖
// 内部调用了 new Function(...)

Так что можно сказать, что вnewВ процессе добавляются новые объекты_proto_и связан с прототипом конструктора.

новый процесс

  1. вновь созданный объект
  2. ссылка на прототип
  3. связать это
  4. вернуть новый объект

вызовnewВышеупомянутые четыре вещи произойдут в процессе, мы также можем попытаться реализовать одну из них самостоятельно.new

function create() {
    // 创建一个空的对象
    let obj = new Object()
    // 获得构造函数
    let Con = [].shift.call(arguments)
    // 链接到原型
	obj.__proto__ = Con.prototype
    // 绑定 this,执行构造函数
    let result = Con.apply(obj, arguments)
    // 确保 new 出来的是个对象
    return typeof result === 'object' ? result : obj
}

Например, объекты, оба передаются черезnewпроизводится, будь тоfunction Foo()все ещеlet a = { b : 1 }.

Для создания объекта рекомендуется использовать литеральный метод для создания объекта. потому что ты используешьnew Object()Способ создания объекта должен быть найден слой за слоем через цепочку областей видимости.Object, но то, как вы используете литералы, не имеет этой проблемы.

function Foo() {}
// function 就是个语法糖
// 内部等同于 new Function()
let a = { b: 1 }
// 这个字面量内部也是使用了 new Object()

Function.proto === Function.prototype

Для объектов,xx.__proto__.contrcutorявляется конструктором объекта, но на рисунке мы можем найтиFunction.__proto__ === Function.prototype, значит ли это, чтоFunctionпроизвел сам?

Ответ определенно нет. Чтобы объяснить эту проблему, мы сначала начнем сObjectГоворя о.

Из рисунка видно, что все объекты в конечном итоге можно найти через цепочку прототипов.Object.prototype,Несмотря на то чтоObject.prototypeтоже объект, но этот объект неObjectсоздается самим двигателемObject.prototype.Таким образом, можно сказать, что все экземпляры являются объектами, но объекты не обязательно являются всеми экземплярами.

Далее мы смотрим наFunction.prototypeЭтот специальный объект, если вы распечатаете этот объект в браузере, вы обнаружите, что этот объект на самом деле является функцией.

Мы знаем, что функции передаются черезnew Function()генерируется, что лиFunction.prototypeтакже черезnew Function()производится? Ответа тоже нет, эта функция тоже создается самим движком. Сначала создается двигательObject.prototype, затем созданFunction.prototype, и через__proto__Соедините два. Вот также хорошее объяснение одной из вышеперечисленных проблем, почемуlet fun = Function.prototype.bind()нетprototypeАтрибуты. так какFunction.prototypeЭто объект, созданный движком, движок считает, что к этому объекту добавлять ничего не нужно.prototypeАтрибуты.

Таким образом, можно сделать вывод, что не все функцииnew Function()произведено.

имеютFunction.prototypeтолько позжеfunction Function(), а затем другие конструкторыfunction Function()Сгенерировано.

теперь могу объяснитьFunction.__proto__ === Function.prototypeЭта проблема. потому что первыйFunction.prototypeпозжеfunction Function(), так что парадокса курицы и яйца нет. почемуFunction.__proto__будет равноFunction.prototype, личное понимание таково: все остальные конструкторы можно найти через цепочку прототиповFunction.prototypefunction Function()Суть это тоже функция, чтобы не вводить в заблуждениеfunction Function()из__proto__связалсяFunction.prototypeначальство.

Суммировать

  • Objectпапа всех объектов, все объекты могут проходить через__proto__Найди это
  • Functionявляется папой всех функций, и все функции могут быть переданы через__proto__Найди это
  • Function.prototypeиObject.prototypeэто два специальных объекта, которые создаются движком
  • За исключением двух указанных выше специальных объектов, другие объекты передаются через конструктор.newот
  • функциональныйprototypeобъект, прототип
  • объект__proto__указать на прототип,__proto__Соединение объектов и прототипов образует цепочку прототипов.