Подготовка к собеседованию 2019 — JS-прототипы и цепочки прототипов

JavaScript опрос

Create by jsliang on 2019-2-21 08:42:02
Recently revised in 2019-2-23 09:44:08

Привет друзья, если вы считаете, что эта статья неплохая, не забудьте датьstar, ВашstarЭто моя мотивация учиться!Адрес GitHub


【2019-08-16】Привет друзья, потому чтоjsliangБиблиотека документации подверглась рефакторингу, некоторые ссылки на эту статью могут быть битыми, иjsliangУ меня нет сил поддерживать старые статьи на стороне Nuggets, извините за это. Для тех, кому нужно получать последние статьи, щелкните адрес GitHub выше и перейдите в библиотеку документов, чтобы просмотреть скорректированные статьи.


Эта статья включает в себя очки знаний:

  • prototype
  • __proto__
  • new
  • call()/apply()/bind()
  • this

В этой статье jsliang объяснит свое личное понимание вышеуказанных знаний посредством самоисследования.Если есть какие-либо ошибки, упущения или недоразумения, вы можете оставить сообщение и указать на это.

Если у вас есть какие-либо вопросы по статье, вы хотите получить быстрый ответ.
Или небольшой партнер интересуется личной библиотекой внешних документов jsliang, а также хочет разобраться в своих внешних знаниях.
Добро пожаловать в группу QQ для совместного обсуждения:798961601.

каталог

Чем отличается передок без закидывания от соленой рыбы?

содержание
каталог
2 Предисловие
три темы
Решение четырех проблем
Развитие пяти знаний
5.1 Проблемные подростки: путешествие начинается
5.2 Прототипы и цепочки прототипов
5.3 Что нового
5.4 Что такое call()?
5.5 Где находится эта точка
Шесть резюме
7 ссылок
Восемь инструментов

2 Предисловие

Назад к содержанию

Когда мой друг в Гуанчжоу помогал мне с интервью, он задал вопрос:Можете ли вы рассказать о том, что это делает?

Цель темы:

  1. Поймите это и расскажите о роли этого.
  2. Переменная Vue this., где this указывает на Vue. (имеется в виду экземпляр Vue)
  3. Напишите setTimeout в Vue и обнаружите, что это меняется (call(),apply(),=>)
  4. ... примерно так...

Однако я обнаружил, что выбрал дорогу, из которой нет возврата, и случайно взглянул на нее.prototype!

Затем я взобрался на высокую гору...

три темы

Назад к содержанию

Я считаю, что некоторые друзья могут уверенно ответить на следующие вопросы~

  • Тема 1
var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {
  n: 2,
  m: 3
}
var c = new A();

console.log(b.n);
console.log(b.m);

console.log(c.n);
console.log(c.m);

Пожалуйста, напишите, каков результат вышеуказанного программирования?

  • Тема 2
var F = function() {};

Object.prototype.a = function() {
  console.log('a');
};

Function.prototype.b = function() {
  console.log('b');
}

var f = new F();

f.a();
f.b();

F.a();
F.b();

Пожалуйста, напишите, каков результат вышеуказанного программирования?

  • Тема 3
function Person(name) {
    this.name = name
}
let p = new Person('Tom');

Вопрос 1: 1. Чему равно p.__proto__?

Вопрос 2: Чему равно Person.__proto__?

  • Тема 4
var foo = {},
    F = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';

console.log(foo.a);
console.log(foo.b);

console.log(F.a);
console.log(F.b);

Пожалуйста, напишите, каков результат вышеуказанного программирования?

Решение четырех проблем

Назад к содержанию

  • Ответ на вопрос 1:
b.n -> 1
b.m -> undefined;

c.n -> 2;
c.m -> 3;
  • Ответы на вопрос 2:
f.a() -> a
f.b() -> f.b is not a function

F.a() -> a
F.b() -> b
  • Тема 3 ответа

Ответ 1: Person.prototype

Ответ 2: Function.prototype

  • Вопрос 4 Ответы
foo.a => value a
foo.b => undefined
F.a => value a
F.b => value b

Если вы, ребята, все еще не знаете, что происходит после проверки ответов, давайте расширим наши знания и узнаем об этом больше!

Развитие пяти знаний

Назад к содержанию

Прототипы и цепочки прототипов, вероятно, являются старомодными темами, но все еще есть много новичков (таких какjsliangсам) здесь часто ошеломлен.

Первая картина поклонения предкам, пусть буря грянет сильнее!

5.1 Проблемные подростки: путешествие начинается

Назад к содержанию

Из-за любви (понимания подноготной), такjsliangНачните свое обучение (Baidu), чтобы узнать о прототипах и цепочках прототипов.

первый,jsliangузнать о цепочке прототиповprototype.

потом, увидел по путиnew, так что Baidu смотрит на JSnewидея.

тогда,трогатьnewпоймет иcall(),а такжеcall(),apply()и стрелочные функции=>Это похоже на что-то.

наконец, когда мы смотрим вверхcall(), он снова включаетthis, так что мы "кстати" смотрим вверхthisБар.

5.1 Прототипы и цепочки прототипов

Назад к содержанию

первый, Зачем нужны прототипы и цепочки прототипов?

Давайте посмотрим на пример:

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.eat = function() {
    console.log(age + "岁的" + name + "在吃饭。");
  }
}

let p1 = new Person("jsliang", 24);
let p2 = new Person("jsliang", 24);

console.log(p1.eat === p2.eat); // false

Видно, что для той же функции мы переходимnewСгенерированный экземпляр откроет новую область кучи, поэтому приемы пищи человека 1 и человека 2 в приведенном выше коде отличаются.

Хорошо владеть вещами, которые принадлежат вам (например, дом, машина). Но есть и минусы, ведь земли (памяти) всего-то и так-то много, строишь дома, а в итоге нет свободной земли? (Недостаточно места)

Итак, давайте подумаем, как построить объект, похожий на разделяемую библиотеку (например, построить здание выше), чтобы при необходимости мы могли вызвать объект (сообщество), похожий на разделяемую библиотеку, чтобы экземпляр мог следовать определенные подсказки, чтобы найти, где вы принадлежите.

И эта подсказка во внешнем интерфейсе — цепочка прототипов.prototype.

function Person(name) {
  this.name = name;
}

// 通过构造函数的 Person 的 prototype 属性找到 Person 的原型对象
Person.prototype.eat = function() {
  console.log("吃饭");
}

let p1 = new Person("jsliang", 24);
let p2 = new Person("梁峻荣", 24);

console.log(p1.eat === p2.eat); // true

Смотреть! Таким образом, мы позволяем этим двум объектам-экземплярам указывать на одно и то же место (сообщество) в форме совместного использования.

потом, Сказав это, мы заинтересованы,prototypeЧто это такое? Это так потрясающе!

У ребенка нет матери, это долгая история. Прежде всего, нам предстоит начать с рождения JavaScript, но если вы поместите его сюда, то основная сюжетная линия будет слишком длинной, поэтому вот театральная версия этой статьи.«Рождение всего в мире JavaScript», и заинтересованные друзья могут пойти узнать. Здесь мы еще посмотрим на картинку и вернемся к этой теме:

  • JS сказал, я так одинок. Потому что происхождение JS пусто, то есть: ноль.
  • JS говорит, есть бог. так что проходит панацея__proto__Родился бог №1, а именно:No1.__proto__ == null.
  • ДС сказал: «Боже, у тебя должны быть свои собственные идеи. Так что сам Бог придумал метод, основанный на его собственном прототипеprototypeобъект созданObject,который:Object.prototype == No1; No1.__proto__ == null. Итак, мы положилиprototypeЭто называется прототипом, напримерObjectПрототип человека — Бог, архетип человека такой же, как у человека, и в то же время__proto__Это называется цепочкой прототипов, ведь существует__proto__, есть только связь между объектами, богами и JS. В этот моментObject.prototype.__proto__ == null.
  • Я сказал, что Бог у тебя больше идей, ах, я ставлю всеобщую хирургию__proto__Я позаимствовал его у вас. Итак, Бог основан наObject,использовать__proto__Сделал машину №2, т.е.No2.__proto__ == No1, и предписывает все через__proto__Вы можете подключиться к машине и найти себя, в том числеObjectда такОбъект стал прототипом для всех объектов,Object.__proto__.__proto__ == No1,ПотомString,Number,Boolean,ArrayТо же самое касается и этих видов.
  • JS сказал: «Боже, твоя машина потрясающая! Может ли ваша машина производить больше машин? Бог усмехнулся: Ты сотворил меня всемогуществом, а я сотворил предметы своим собственным архетипом. Итак, затем я создаю функцию машины,Function.prototype == No2, Function.__proto__ == No2,Прямо сейчасFunction.prototype == Function.__proto__Бар! Таким образом, No2 становится машиной, которая создает машину, отвечающую за управление объектами, функциями, строками, числами, логическими значениями и массивами.

наконец, Говоря об этом, мы должны иметь хорошее представление о картине поклонения предкам в начале, чувствовать себя немного просветленным и ясно понимать следующие формулы:

Object.__proto__ === Function.prototype;
Function.prototype.__proto__ === Object.prototype;
Object.prototype.__proto__ === null;

5.3 Что нового

Назад к содержанию

В это время мы знаемprototypeтак же как__proto__Что случилось, вернемся к предыдущему коду:

function Person(name) {
  this.name = name;
}

// 通过构造函数的 Person 的 prototype 属性找到 Person 的原型对象
Person.prototype.eat = function() {
  console.log("吃饭");
}

let p1 = new Person("jsliang", 24);
let p2 = new Person("梁峻荣", 24);

console.log(p1.eat === p2.eat); // true

Видно, что здесь есть точка, которую мы пока не знаем, а именно:новый для чего?

первый, поговорим о функции:Функции делятся на конструкторы и обычные функции.

В чем дело?Стартовая машина №2В процессе создания машинной функции было создано слишком много машин.Чтобы легко отличить эти машины,№1 БогРазделите машины на две категории:Функции класса Creation называются конструкторами (обычно объектно-ориентированными), а функции создания классов Action называются обычными функциями (обычно процедурно-ориентированными).. Чтобы провести аналогию:function Birl() {},function Person() {}Этот тип определения в виде заглавной буквы, используемый для определения определенного вида вида, называетсяКонструктор. а такжеfunction fly() {},function eat() {}Этот тип определения в виде строчной буквы, используемый для определения действия, называется обычной функцией.

Обратите внимание, что они все еще по существу из Function, просто для удобства различия мы называем их так

потом, пробуем сделать летящую птицу:

// 定义鸟类
function Bird(color) {
  this.color = color;
}

// 定义飞的动作
function fly(bird) {
  console.log(bird + " 飞起来了!");
}

тогда, мы собираемся использовать машину для птиц, чтобы создать птицу,№1 БогПочесал затылок и бросил(Обратите внимание, что он бросил), скажите нам использоватьnewНу вот так:

// 定义鸟类
function Bird(color) {
  this.color = color;
}

// 创造一只鸟
let bird1 = new Bird('蓝色');

// 定义飞的动作
function fly(bird) {
  console.log(bird.color + "的鸟飞起来了!");
}

fly(bird1); // 蓝色的鸟飞起来了!

Сказав это, мы знаем, как использовать типы для создания машин и действия для создания машин.

наконец, если нам интересно, мы также можем наблюдать№1 БогсуществуетnewЧто происходит внутри:

Предположим, мы используем:let bird1 = new Bird('蓝色');

// 1. 首先有个类型机器
function ClassMachine() {
  console.log("类型创造机器");
}
// 2. 然后我们定义一个对象物品
let thingOne = {};
// 3. 对象物品通过万能术 __proto__ 指向了类型机器的原型(即 No 2 始机器)
thingOne.__proto__ = ClassMachine.prototype;
// 4. ???
ClassMachine.call(thingOne);
// 5. 定义了类型机器的动作
ClassMachine.prototype.action = function(){
  console.log("动作创造机器");
}
// 6. 这个对象物品执行了动作
thingOne.action();
/*
 * Console:
 * 类型创造机器
 * 动作创造机器
*/

ХОРОШО,newчто ты сделал,No 1Божий замысел ясен.

Тогда следующий пример нам будет понятен:

function Person(name){
    this.name = name
}

Person.prototype = {
  eat:function(){
    console.log('吃饭')
  },
  sleep:function(){
    console.log('睡觉')
  }
};

let p = new Person('梁峻荣',28);

// 访问原型对象
console.log(Person.prototype);
console.log(p.__proto__); // __proto__仅用于测试,不能写在正式代码中

/* Console
  * {eat: ƒ, sleep: ƒ}
  * {eat: ƒ, sleep: ƒ}
*/

Так много людей дадут формулу:

пример__proto__Собственность (прототип) равен его конструкторуprototypeАтрибуты.

Теперь я правильно понимаю!

Однако вы замечаетеnewЭто был пункт 4 в процессе? ! ! !

5.4 Что такое call()?

Назад к содержанию

В пункте 4 мы использовалиcall()Сюда.

Так,call()Что это такое?

первый, нам нужно знатьcall()метод присутствует вFuncitonсередина,Function.prototype.callдаƒ call() { [native code] }, Младший партнер на консоли может его распечатать.

потом, наблюдаем следующий код:

function fn1() {
  console.log(1);
  this.num = 111;
  this.sayHey = function() {
    console.log("say hey.");
  }
}
function fn2() {
  console.log(2);
  this.num = 222;
  this.sayHello = function() {
    console.log("say hello.");
  }
}
fn1.call(fn2); // 1

fn1(); // 1
fn1.num; // undefined
fn1.sayHey(); // fn1.sayHey is not a function

fn2(); // 2
fn2.num; // 111
fn2.sayHello(); // fn2.sayHello is not a function

fn2.sayHey(); //say hey.

пройти черезfn1.call(fn2), мы обнаруживаемfn1,fn2был изменен,call()Это как младший, разрушающийfn1а такжеfn2Гармоничная семья.

Сейчас,fn1Ничего, кроме печати собственной консоли. а такжеfn2имеютfn1Все кроме консоли:numтак же какsayHello.

Помните: здесь,call()Изменил суть.

потом, мы должны взглянуть на его исходный код и понять, как он реализован, ноjsliangTaicai, я не могу понять онлайн-статьи о процессе исходного кода, поэтому давайте добавим еще несколько примеров, чтобы понятьcall()Что я могу сделать~

  • Пример 1:
function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

let food1 = new Food('chees', 5);

food1; // Food {name: "chees", price: 5, category: "food"}

Видно, что поFoodвызвать конструкторcall(), успешноFoodрасширенныйnameтак же какpriceэти два поля. так:

Правило 1: можно использоватьcall()Метод вызывает родительский конструктор.

  • Пример 2:
var animals = [
  {
    species: 'Lion',
    name: 'King'
  },
  {
    species: 'Whale',
    name: 'Fail'
  }
]

for(var i = 0; i < animals.length; i++) {
  (function(i) {
    this.print = function() {
      console.log('#' + i + ' ' + this.species + ": " + this.name);
    }
    this.print();
  }).call(animals[i], i);
}

// #0 Lion: King
// #1 Whale: Fail

Как видите, в анонимной функции мы передаемcall(), успех будетanimalsсерединаthisУказывает на анонимную функцию, которая выводит значение в цикле.

Правило 2: Используйтеcall()метод вызывает анонимные функции.

  • Пример 3:
function greet() {
  var reply = [this.animal, 'typically sleep between', this.sleepDuration].join(' ');
  console.log(reply);
}

var obj = {
  animal: 'cats',
  sleepDuration: '12 and 16 hours'
};

greet.call(obj);  // cats typically sleep between 12 and 16 hours

Правило 3: Используйтеcall()метод вызывает функцию и указывает контекстthis.

наконец, Говоря об этом, друзья должны знатьcall()некоторые виды использования.

Говоря оcall(), мы тоже говорим о чем-то похожем на этоapply(), на самом деле, оба похожи, ноapply()Называется по-разному, например:

function add(a, b){
  return a + b;  
}
function sub(a, b){
  return a - b;  
}

// apply() 的用法
var a1 = add.apply(sub, [4, 2]); // sub 调用 add 的方法
var a2 = sub.apply(add, [4, 2]);

a1; // 6     
a2; // 2

// call() 的用法
var a1 = add.call(sub, 4, 2);

Да,apply()Может вызываться только с двумя аргументами: newthisобъект и массивargArray. который:function.call(thisObj, [arg1, arg2]);

над,мы знаемapply()а такжеcall()Все они существуют для изменения контекста, в котором выполняется функция (то есть для изменения внутреннегоthisнаправление). Затем, поскольку эти два метода вызываются немедленно, чтобы компенсировать их отсутствие, существует методbind(), он не вызывает немедленно:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>call()、apply() 以及 bind()</title>
</head>
<body>
  <div id="box">我是一个盒子!</div>
  
  <script>
    window.onload = function() {
      var fn = {
        num: 2,
        fun: function() {
          document.getElementById("box").onclick = (function() {
            console.log(this.num);
          }).bind(this);
          // }).call(this);
          // }).apply(this);
        }
        /*
         * 这里的 this 是 fun,所以可以正确地访问 num,
         * 如果使用 bind(),会在点击之后打印 2;
         * 如果使用 call() 或者 apply(),那么在刷新网页的时候就会打印 2
        */
      }
      fn.fun();
    }
  </script>
</body>
</html>

Подумайте еще раз, почемуcall(),apply()Ну, мы найдем это вовлеченнымthisи стрелочные функции (=>), так что давайте знакомиться~

5.5 Где находится эта точка

Назад к содержанию

  • В большинстве случаев способ вызова функции определяетthisценность . это в глобальной среде выполненияthisоба указывают на глобальный объект

Как это понять, разберем на примере:

// 在浏览器中, window 对象同时也是全局对象
conosle.log(this === window); // true

a = 'apple';
conosle.log(window.a); // apple

this.b = "banana";
console.log(window.b); // banana
console.log(b); // banana

Однако в повседневной работе большинствоthis, вызываются внутри функции, а:

  • Внутри функции,thisЗначение зависит от того, как была вызвана функция.
function showAge(age) {
  this.newAge = age;
  console.log(newAge);
}
showAge("24"); // 24

Однако всегда есть проблемы:

  • в общемthisУкажите на проблему, которая произойдет в функции обратного вызова. Поэтому, когда мы пишем функцию обратного вызова, мы должны обратить внимание наthisуказывая на проблему.
var obj = {
  birth: 1995,
  getAge: function() {
    var b = this.birth; // 1995;
    var fn = function() {
      return this.birth; 
      // this 指向被改变了!
      // 因为这里重新定义了个 function,
      // 假设它内部有属于自己的 this1,
      // 然后 getAge 的 this 为 this2,
      // 那么,fn 当然奉行就近原则,使用自己的 this,即:this1
    };
    return fn();
  }
}

obj.getAge(); // undefined

Здесь мы можем видеть,fnсерединаthisточка, чтобы статьundefined.

Конечно, у нас есть лекарства.

первый, мы используем упомянутый вышеcall():

var obj = {
  birth: 1995,
  getAge: function() {
    var b = this.birth; // 1995
    var fn = function() {
      return this.birth; 
    };
    return fn.call(obj); // 通过 call(),将 obj 的 this 指向了 fn 中
  }
}

obj.getAge(); // 1995

потом,Мы используемthatприйти забратьthis:

var obj = {
  birth: 1995,
  getAge: function() {
    var b = this.birth; // 1995
    var that = this; // 将 this 指向丢给 that
    var fn = function() {
      return that.birth; // 通过 that 来寻找到 birth
    };
    return fn();
  }
}

obj.getAge(); // 1995

мы прошлиvar that = this, успех вfnпроцитировано вobjизbirth.

наконец, мы также можем использовать стрелочные функции=>:

var obj = {
  birth: 1995,
  getAge: function() {
    var b = this.birth; // 1995
    var fn = () => this.birth;
    return fn();
  }
}
obj.getAge(); // 1995

Сказав это, давайте оглянемся назадnewЧасть кода, которую мы не понимаем:

// 1. 首先有个类型机器
function ClassMachine() {
  console.log("类型创造机器");
}
// 2. 然后我们定义一个对象物品
let thingOne = {};
// 3. 对象物品通过万能术 __proto__ 指向了类型机器的原型(即 No 2 始机器)
thingOne.__proto__ = ClassMachine.prototype;
// 4. ???
ClassMachine.call(thingOne);
// 5. 定义了类型机器的动作
ClassMachine.prototype.action = function(){
  console.log("动作创造机器");
}
// 6. 这个对象物品执行了动作
thingOne.action();
/*
 * Console:
 * 类型创造机器
 * 动作创造机器
*/

Это легко понять, на четвертом шаге мы будемClassMachineизthisсталthingOneизthis!

Вышесказанное, чувствуете ли вы, что врата ада были закрыты на некоторое время, и, наконец, вам удалось увидеть рассвет! ! !

Шесть резюме

Назад к содержанию

Вначале, возможно, у некоторых друзей закружится голова, когда они увидят это!

Неважно, я тоже!

Когда я следовал своим собственным идеям и сбивал их шаг за шагом, я понял, что, кажется, открыл две вены Рена и Ду, и у меня появилось собственное понимание некоторых тем.

Итак, самое главное,жеребьевкаЛа!

после всего:

Какая разница между передком без заброса и соленой рыбой!

Семь ссылок

Назад к содержанию

Ниже приведен список избранных справочных статей в этой статье, некоторые из которых не важны и разрознены.Было отобрано более 30 статей.

Восемь инструментов

Назад к содержанию

知识共享许可协议
библиотека документации jsliangЗависит отЛян ЦзюньронгиспользоватьCreative Commons Attribution - NonCommercial-Sharealike 4.0 Международная лицензияЛицензия.
на основеGitHub.com/l ian Jun Ron…Создание работ выше.
Права на использование, отличные от разрешенных в настоящем Лицензионном соглашении, могут быть получены отCreative Commons.org/licenses/не…получено в.