Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?

интервью внешний интерфейс JavaScript Vue.js

предисловие

Привет, яВакагава. Это первое из серии интервьюеров, которых попросили помочь читателям улучшитьJSбазовые знания, в том числеnew、call、apply、this、继承связанная информация.

面试官问系列Статья выглядит следующим образом: Заинтересованные читатели могут нажать, чтобы прочитать.

1.Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?
2.Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?
3.Интервьюер спросил: Могу ли я смоделировать вызов и применить методы JS?
4.Интервьюер спросил: этот пункт JS
5.Интервьюер спросил: наследование JS

использовалVuejsВсе учащиеся знают, что необходимо использоватьnewоператор для создания экземпляра.

new Vue({
    el: '#app',
    mounted(){},
});

Затем интервьюер может спросить,newЧто именно он делал и как это имитировать.

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

что нового сделал

Сначала простоПример 1:

// 例子1
function Student(){
}
var student = new Student();
console.log(student); // {}
// student 是一个对象。
console.log(Object.prototype.toString.call(student)); // [object Object]
// 我们知道平时声明对象也可以用new Object(); 只是看起来更复杂
// 顺便提一下 `new Object`(不推荐)和Object()也是一样的效果
// 可以猜测内部做了一次判断,用new调用
/** if (!(this instanceof Object)) {
*    return new Object();
*  }
*/
var obj = new Object();
console.log(obj) // {}
console.log(Object.prototype.toString.call(student)); // [object Object]

typeof Student === 'function' // true
typeof Object === 'function' // true

Из этого примера мы видим, что функция сnewПосле вызова оператора создается новый объект. иStudentиObjectявляются функциями, ноStudentнаш обычай,ObjectдаJSвстроенный в себя. Давайте посмотрим на диаграмму вывода в консоль, желающие могут попробовать ее на консоли.例子1 控制台输出图иnew Object()Сгенерированный объект отличаетсяnew Student()Также есть слой вложенности в середине сгенерированного объекта__proto__,этоconstructorдаStudentэта функция.

// 也就是说:
student.constructor === Student;
Student.prototype.constructor === Student;

Вывод 1. Из этого простого примераnewОператор делает две вещи:

  1. Создается новый объект.
  2. Этот объект будет выполнен[[Prototype]](это,__proto__)Ссылка на сайт.

Далее давайте посмотрим на обновленную версиюПример 2:

// 例子2
function Student(name){
    console.log('赋值前-this', this); // {}
    this.name = name;
    console.log('赋值后-this', this); // {name: '若川'}
}
var student = new Student('若川');
console.log(student); // {name: '若川'}

Видно, что: здесьStudentв функцииthisнаправлениеnew Student()сгенерированный объектstudent.

Резюме 2: Из этого примераnewОператор делает еще одну вещь:

  1. Результирующий новый объект привязывается к вызову функцииthis.

Далее продолжаем смотреть на обновленную версиюПример 3:

// 例子3
function Student(name){
    this.name = name;
    // this.doSth();
}
Student.prototype.doSth = function() {
    console.log(this.name);
};
var student1 = new Student('若');
var student2 = new Student('川');
console.log(student1, student1.doSth()); // {name: '若'} '若'
console.log(student2, student2.doSth()); // {name: '川'} '川'
student1.__proto__ === Student.prototype; // true
student2.__proto__ === Student.prototype; // true
// __proto__ 是浏览器实现的查看原型方案。
// 用ES5 则是:
Object.getPrototypeOf(student1) === Student.prototype; // true
Object.getPrototypeOf(student2) === Student.prototype; // true

例子3 控制台输出图Что касается отношений прототипа JS, я видел эту картинку раньше, и я подумал, что это очень хорошо, я поделюсь ею с вами.JavaScript原型关系图

Резюме 3: Этот пример 3 еще раз доказываетРезюме 1серединапункт 2. То есть объект будет выполнен[[Prototype]](это,__proto__)Ссылка на сайт. и черезnew Student()Каждый созданный объект в конечном итоге будет[[Prototype]]ссылка на этоStudent.protytypeна объекте.

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

// 例子4
function Student(name){
    this.name = name;
    // Null(空) null
    // Undefined(未定义) undefined
    // Number(数字) 1
    // String(字符串)'1'
    // Boolean(布尔) true
    // Symbol(符号)(第六版新增) symbol
    
    // Object(对象) {}
        // Function(函数) function(){}
        // Array(数组) []
        // Date(日期) new Date()
        // RegExp(正则表达式)/a/
        // Error (错误) new Error() 
    // return /a/;
}
var student = new Student('若川');
console.log(student); {name: '若川'}

После того, как автор протестировал эти семь типовТипы JavaScript MDN, результат: первые шесть основных типов возвращаются нормально{name: '若川'},НазадObject(ВключаютFunctoin, Array, Date, RegExg, Error) вернет эти значения напрямую.

Это приводит к выводу 4:

  1. Если функция не возвращает тип объектаObject(ВключаютFunctoin, Array, Date, RegExg, Error),ТакnewВызовы функций в выражениях автоматически возвращают этот новый объект.

Объединение этих резюме вместе:

  1. Создается новый объект.
  2. Этот объект будет выполнен[[Prototype]](это,__proto__)Ссылка на сайт.
  3. Результирующий новый объект привязывается к вызову функцииthis.
  4. пройти черезnewКаждый созданный объект в конечном итоге будет[[Prototype]]ссылка на эту функциюprototypeна объекте.
  5. Если функция не возвращает тип объектаObject(ВключаютFunctoin, Array, Date, RegExg, Error),ТакnewВызовы функций в выражениях автоматически возвращают этот новый объект.

новая фиктивная реализация

Зная эти явления, мы можем смоделироватьnewоператор. Почтовый код и комментарии напрямую

/**
 * 模拟实现 new 操作符
 * @param  {Function} ctor [构造函数]
 * @return {Object|Function|Regex|Date|Error}      [返回结果]
 */
function newOperator(ctor){
    if(typeof ctor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }
    // ES6 new.target 是指向构造函数
    newOperator.target = ctor;
    // 1.创建一个全新的对象,
    // 2.并且执行[[Prototype]]链接
    // 4.通过`new`创建的每个对象将最终被`[[Prototype]]`链接到这个函数的`prototype`对象上。
    var newObj = Object.create(ctor.prototype);
    // ES5 arguments转成数组 当然也可以用ES6 [...arguments], Aarry.from(arguments);
    // 除去ctor构造函数的其余参数
    var argsArr = [].slice.call(arguments, 1);
    // 3.生成的新对象会绑定到函数调用的`this`。
    // 获取到ctor函数返回结果
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    // 小结4 中这些类型中合并起来只有Object和Function两种类型 typeof null 也是'object'所以要不等于null,排除null
    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    // 5.如果函数没有返回对象类型`Object`(包含`Functoin`, `Array`, `Date`, `RegExg`, `Error`),那么`new`表达式中的函数调用会自动返回这个新的对象。
    return newObj;
}

Наконец-то реализовано с помощью моделированияnewOperatorфункция проверки предыдущегоПример 3:

// 例子3 多加一个参数
function Student(name, age){
    this.name = name;
    this.age = age;
    // this.doSth();
    // return Error();
}
Student.prototype.doSth = function() {
    console.log(this.name);
};
var student1 = newOperator(Student, '若', 18);
var student2 = newOperator(Student, '川', 18);
// var student1 = new Student('若');
// var student2 = new Student('川');
console.log(student1, student1.doSth()); // {name: '若'} '若'
console.log(student2, student2.doSth()); // {name: '川'} '川'

student1.__proto__ === Student.prototype; // true
student2.__proto__ === Student.prototype; // true
// __proto__ 是浏览器实现的查看原型方案。
// 用ES5 则是:
Object.getPrototypeOf(student1) === Student.prototype; // true
Object.getPrototypeOf(student2) === Student.prototype; // true

видно что подходитnewоператор. Читатели могут указать, что не так или что можно улучшить. Просмотрите эту симуляциюnewфункцияnewOperatorРеализация, самый большой вклад должен принадлежатьObject.create()этоES5который предоставилAPI.

Пример использования Object.create()

Я также упомянул об этом в статье, которую я составил ранее, вы можете прочитать ееВесь API-анализ объектов JavaScript

MDN Object.create()

Object.create(proto, [propertiesObject])метод создает новый объект, используя существующий объект для предоставления __proto__ вновь созданного объекта. Он принимает два параметра, но вторым необязательным параметром является дескриптор атрибута (обычно не используется, по умолчаниюundefined).

var anotherObject = {
    name: '若川'
};
var myObject = Object.create(anotherObject, {
    age: {
        value:18,
    },
});
// 获得它的原型
Object.getPrototypeOf(anotherObject) === Object.prototype; // true 说明anotherObject的原型是Object.prototype
Object.getPrototypeOf(myObject); // {name: "若川"} // 说明myObject的原型是{name: "若川"}
myObject.hasOwnProperty('name'); // false; 说明name是原型上的。
myObject.hasOwnProperty('age'); // true 说明age是自身的
myObject.name; // '若川'
myObject.age; // 18;

для не поддерживаемыхES5браузер,MDNпредоставляется наployfillплан.

if (typeof Object.create !== "function") {
    Object.create = function (proto, propertiesObject) {
        if (typeof proto !== 'object' && typeof proto !== 'function') {
            throw new TypeError('Object prototype may only be an Object: ' + proto);
        } else if (proto === null) {
            throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
        }

        if (typeof propertiesObject != 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");

        function F() {}
        F.prototype = proto;
        return new F();
    };
}

На этом статья в основном закончена. Спасибо читателям, что увидели это.

Наконец, чтобы подвести итог:

  1. newЧто вы наделали:
  1. Создается новый объект.
  2. Этот объект будет выполнен[[Prototype]](это,__proto__)Ссылка на сайт.
  3. Результирующий новый объект привязывается к вызову функцииthis.
  4. пройти черезnewКаждый созданный объект в конечном итоге будет[[Prototype]]ссылка на эту функциюprototypeна объекте.
  5. Если функция не возвращает тип объектаObject(ВключаютFunctoin, Array, Date, RegExg, Error),ТакnewВызовы функций в выражениях автоматически возвращают этот новый объект.
  1. как имитировать
// 去除了注释
function newOperator(ctor){
    if(typeof ctor !== 'function'){
      throw 'newOperator function the first param must be a function';
    }
    newOperator.target = ctor;
    var newObj = Object.create(ctor.prototype);
    var argsArr = [].slice.call(arguments, 1);
    var ctorReturnResult = ctor.apply(newObj, argsArr);
    var isObject = typeof ctorReturnResult === 'object' && ctorReturnResult !== null;
    var isFunction = typeof ctorReturnResult === 'function';
    if(isObject || isFunction){
        return ctorReturnResult;
    }
    return newObj;
}

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

Избранные статьи автора

Изучите общую архитектуру исходного кода sentry и создайте собственный SDK для мониторинга исключений переднего плана.
Изучите общую архитектуру исходного кода lodash и создайте собственную библиотеку классов функционального программирования.
Изучите общую архитектуру исходного кода подчеркивания и создайте собственную библиотеку классов функционального программирования.
Изучите общую архитектуру исходного кода jQuery и создайте собственную библиотеку js.
Интервьюер спросил: наследование JS
Интервьюер спросил: этот пункт JS
Интервьюер спросил: Могу ли я смоделировать вызов и применить методы JS?
Интервьюер спросил: Могу ли я смоделировать метод привязки, реализующий JS?
Интервьюер спросил: Могу ли я смоделировать новый оператор, реализующий JS?
Внешний интерфейс использует сканер puppeteer для создания PDF-файла «React.js Book» и его слияния.

о

Автор: Чанг ИВакагаваНазвание смешано в реках и озерах. По дороге на фронт | Энтузиасты РРТ | Знаю очень мало, только хорошо учусь.
личный блог
segmentfaultПередняя колонка обзора, открылПередний планКолонка, добро пожаловать на внимание~
Колонка самородков, добро пожаловать, обратите внимание~
Знайте переднюю колонку видения, открылПередний планКолонка, добро пожаловать на внимание~
github blog, спроситьstar^_^~

Публичный аккаунт WeChat Ruochuan Vision

[Видение Вакагава] Публичный аккаунт Wechat, который может быть интересным, прошу обратить внимание. Вы также можете добавить WeChatruochuan12, укажите источник и втяните вас в [Front-end Vision Exchange Group].