Интервьюер спросил: этот пункт JS

JavaScript опрос

предисловие

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

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

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

Интервьюер задает много тестовых вопросов, и они в основном меняют способ расследования.thisУкажите, см. пару кандидатовJSПрочны ли базовые знания. Читатели могут сначала потянуть вниз, чтобы прочитать резюме, а затем в Google (или на различных технологических платформах) выполнить поиск нескольких похожих статей, чтобы увидеть, чем статьи, написанные автором, отличаются от других (вы можете прокомментировать различия в поле для комментариев).

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

функциональныйthisСвязывание во время вызова полностью зависит от того, где вызывается функция (то есть, как вызывается функция). выяснитьthisНа что указывает указатель, вы должны знать, как вызывается соответствующая функция.

глобальный контекст

Как в обычном, так и в строгом режиме это указывает на объект верхнего уровня (в браузере этоwindow).

this === window // true
'use strict'
this === window;
this.name = '若川';
console.log(this.name); // 若川

контекст функции

Обычный шаблон вызова функции

// 非严格模式
var name = 'window';
var doSth = function(){
    console.log(this.name);
}
doSth(); // 'window'

ты можешь ошибатьсяwindow.doSth()называется, поэтому он указывает наwindow. Хотя в этом примереwindow.doSthравноdoSth.nameравныйwindow.name. В приведенном выше коде это потому, чтоES5, глобальные переменные монтируются на объекты верхнего уровня (браузерwindow)середина. На самом деле это не так.

// 非严格模式
let name2 = 'window2';
let doSth2 = function(){
    console.log(this === window);
    console.log(this.name2);
}
doSth2() // true, undefined

В этом примереletНикакие свойства не добавляются к объекту верхнего уровня (браузер является окном),window.name2和window.doSthобеundefined.

В строгом режиме, в нормальных функцияхthisвести себя по-разному, какundefined.

// 严格模式
'use strict'
var name = 'window';
var doSth = function(){
    console.log(typeof this === 'undefined');
    console.log(this.name);
}
doSth(); // true,// 报错,因为this是undefined

Посмотрел "Ты не знаешь"JavaScript«Читатели предыдущего тома должны знать, что в книге это называется связыванием по умолчанию. правильноcall,applyЗнакомые читатели проведут аналогию:

doSth.call(undefined);
doSth.apply(undefined);

Эффект тот же,call,applyОдной из функций является изменение функции вthisуказывает на первый параметр. Первый параметрundefinedилиnull, в нестрогом режиме относится кwindow. В строгом режиме это относится к первому параметру. Это объяснено подробно позже.
Часто встречается такой код (функция обратного вызова), который на самом деле является обычным режимом вызова функции.

var name = '若川';
setTimeout(function(){
    console.log(this.name);
}, 0);
// 语法
setTimeout(fn | code, 0, arg1, arg2, ...)
// 也可以是一串代码。也可以传递其他函数
// 类比 setTimeout函数内部调用fn或者执行代码`code`。
fn.call(undefined, arg1, arg2, ...);

Паттерн вызова функции (метода) в объекте

var name = 'window';
var doSth = function(){
    console.log(this.name);
}
var student = {
    name: '若川',
    doSth: doSth,
    other: {
        name: 'other',
        doSth: doSth,
    }
}
student.doSth(); // '若川'
student.other.doSth(); // 'other'
// 用call类比则为:
student.doSth.call(student);
// 用call类比则为:
student.other.doSth.call(student.other);

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

var studentDoSth = student.doSth;
studentDoSth(); // 'window'
// 用call类比则为:
studentDoSth.call(undefined);

call、apply、bindрежим вызова

упомянутый вышеcall,apply, читайте здесь подробно. пройти первымMDNузнатьcallа такжеapply Документация MDN: Function.prototype.call()
грамматика

fun.call(thisArg, arg1, arg2, ...)

thisArg
существуетfunуказывается при выполнении функцииthisстоимость. Следует отметить, что указанныйthisЗначение не обязательно верно, что функция фактически выполняется.thisзначение, если эта функция находится внестрогий режимниже он указан какnullа такжеundefinedизthisЗначение будет автоматически указывать на глобальный объект (в браузере этоwindowОбъект), значение является исходным значением (число, строка, логическое значение)thisУкажет на объект с автоматической оболочкой для этого примитивного значения.
arg1, arg2, ...
указанный список параметров
возвращаемое значение
Возвращаемое значение — это возвращаемое значение метода, который вы вызвали. Если у метода нет возвращаемого значения, вернитеundefined.
applyа такжеcallаналогичный. Только параметры разные. Его аргумент представляет собой массив (или подобный массиву).

По параметрамthisArgописание, можно узнать, что,callэто изменить функциюthisуказывает наthisArg, и выполнить функцию, которая также делаетJSМного гибкости. В строгом режиме,thisArgПримитивное значение — это тип значения, то есть примитивное значение. не будет обернут в объект. Например:

var doSth = function(name){
    console.log(this);
    console.log(name);
}
doSth.call(2, '若川'); // Number{2}, '若川'
var doSth2 = function(name){
    'use strict';
    console.log(this);
    console.log(name);
}
doSth2.call(2, '若川'); // 2, '若川'

Хотя в целом неthisArgПараметры записываются как типы значений. Но все же нужно знать эти знания. Я уже писал статью:Интервьюер спросил: Можно ли это смоделировать?JSизcallа такжеapplyметодЭто использовать функцию на объектеthisУкажите на этот объект, чтобы имитировать реализациюcallа такжеapplyиз. Заинтересованные читатели думают, как это реализовать, а потом идут смотреть авторскую реализацию.

bindа такжеcallа такжеapplyАналогично изменяется и первый параметрthisУкажите на, но возвращаемое значение — это новая функция, и новую функцию также можно использовать в качестве конструктора (new)передача.MDN Function.prototype.bind

bind()метод создает новую функцию, когда эта новая функция вызываетсяthisЗначение ключа — это значение, которое он предоставляет, а первые несколько элементов в его списке параметров — это последовательность параметров, указанная при создании.

грамматика: fun.bind(thisArg[, arg1[, arg2[, ...]]])
параметр: thisArgЗначение, передаваемое целевой функции в качестве параметра this при вызове связанной функции. При использованииnewоператор строит связанную функцию, значение игнорируется. когда используешьbindсуществуетsetTimeoutПри создании функции (предоставленной как обратный вызов) вthisArgЛюбое переданное примитивное значение будет преобразовано вobject. Если связанные параметры не указаны,thisрассматривается как новая функцияthisArg.arg1, arg2, ...Когда связанная функция вызывается, эти параметры передаются связанному методу перед фактическими аргументами.возвращаемое значениеВозврат из указанногоthisКопия исходной функции, преобразованная по значению и параметрам инициализации.

Я уже писал статью:Интервьюер спросил: Можно ли это смоделировать?JSизbindметодИспользоватьcallа такжеapplyуказать на этоthisArgпараметры, чтобы имитировать реализациюbindиз. Заинтересованные читатели думают, как это реализовать, а потом идут смотреть авторскую реализацию.

Шаблон вызова конструктора

function Student(name){
    this.name = name;
    console.log(this); // {name: '若川'}
    // 相当于返回了
    // return this;
}
var result = new Student('若川');

использоватьnewОператор вызывает функцию, которая автоматически выполняет следующие действия.

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

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

function Student(name){
    this.name = name;
    // return function f(){};
    // return {};
}
var result = new Student('若川');
console.log(result); {name: '若川'}
// 如果返回函数f,则result是函数f,如果是对象{},则result是对象{}

Многие люди или статьи игнорируют этот момент и используют его прямо и просто.typeofОбъект суда. Хотя возврат не будет показан при фактическом использовании, интервьюер спросит.

Я написал статью раньшеИнтервьюер спросил: Можно ли это смоделировать?JSизnewоператор, заключается в использовании apply, чтобы указать this на сгенерированный вновь сгенерированный объект. Заинтересованные читатели думают, как это реализовать, а потом идут смотреть авторскую реализацию.

Вызов шаблонов в цепочке прототипов

function Student(name){
    this.name = name;
}
var s1 = new Student('若川');
Student.prototype.doSth = function(){
    console.log(this.name);
}
s1.doSth(); // '若川'

Найдет это знакомым. Это шаблон вызова метода для объекта. Естественно, он указывает на сгенерированный новый объект. Если объект наследуется от других объектов. Он также просматривает цепочку прототипов. Используйте приведенный выше кодES6серединаclassПравило написания таково:

class Student{
    constructor(name){
        this.name = name;
    }
    doSth(){
        console.log(this.name);
    }
}
let s1 = new Student('若川');
s1.doSth();

babel es6Перевести вes5, ты можешь пойти вbabeljs网站转换测试Попробуй сам.

'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Student = function () {
    function Student(name) {
        _classCallCheck(this, Student);

        this.name = name;
    }

    _createClass(Student, [{
        key: 'doSth',
        value: function doSth() {
            console.log(this.name);
        }
    }]);

    return Student;
}();

var s1 = new Student('若川');
s1.doSth();

Это показывает,ES6изclassЭто также реализуется через симуляцию конструктора, которая является своего рода синтаксическим сахаром.

Шаблон вызова функции стрелки

Давайте сначала рассмотрим важные различия между стрелочными функциями и обычными функциями:

1. не собственныйthis,super,argumentsа такжеnew.targetсвязывать.

2. Не может быть использованnewзвонить. 3. Нет объекта-прототипа. 4, не может быть измененthisпривязка. 5. Формальное имя параметра не может повторяться.

Стрелочные функции не имеютthisBinding, значение которого необходимо определить, просматривая цепочку областей видимости. Если стрелочная функция содержится в нестрелочной функции, тоthisПривязка — ближайший слой нестрелочных функцийthis,иначеthisВ качестве значения устанавливается глобальный объект. Например:

var name = 'window';
var student = {
    name: '若川',
    doSth: function(){
        // var self = this;
        var arrowDoSth = () => {
            // console.log(self.name);
            console.log(this.name);
        }
        arrowDoSth();
    },
    arrowDoSth2: () => {
        console.log(this.name);
    }
}
student.doSth(); // '若川'
student.arrowDoSth2(); // 'window'

Фактически эквивалентно функции вне стрелокthisэто кэшированная обычная функция верхнего уровня стрелочной функцииthis. Если нормальной функции нет, то это глобальный объект (в браузере этоwindow). То есть пройти невозможноcall,apply,bindсвязать функцию стрелкиthis(это не само по себеthis). а такжеcall,apply,bindМожно привязать обычную функцию верхнего слоя стрелочной функции кэшаthis. Например:

var student = {
    name: '若川',
    doSth: function(){
        console.log(this.name);
        return () => {
            console.log('arrowFn:', this.name);
        }
    }
}
var person = {
    name: 'person',
}
student.doSth().call(person); // '若川'  'arrowFn:' '若川'
student.doSth.call(person)(); // 'person' 'arrowFn:' 'person'

DOMвызов обработчика событий

addEventerListener, attachEvent, по клику

<button class="button">onclick</button>
<ul class="list">
    <li>1</li>
    <li>2</li>
    <li>3</li>
</ul>
<script>
    var button = document.querySelector('button');
    button.onclick = function(ev){
        console.log(this);
        console.log(this === ev.currentTarget); // true
    }
    var list = document.querySelector('.list');
    list.addEventListener('click', function(ev){
        console.log(this === list); // true
        console.log(this === ev.currentTarget); // true
        console.log(this);
        console.log(ev.target);
    }, false);
</script>

onclickа такжеaddEventerListener— элемент, указывающий на связанное событие. некоторые браузеры, напримерIE6~IE8использовать подattachEvent,thisуказать даwindow. Кстати: интервьюер тоже частоev.currentTargetа такжеev.targetразница.ev.currentTargetэто элемент, к которому привязано событие, иev.targetэлемент, который в данный момент запускает событие. Вот, например, разницаulа такжеli. но можно и нажатьul, тогдаev.currentTargetа такжеev.targetРавный.

Функция функции обработчика событий в Inline

<button class="btn1" onclick="console.log(this === document.querySelector('.btn1'))">点我呀</button>
<button onclick="console.log((function(){return this})());">再点我呀</button>

первыйbuttonсам так себеtrue, второйwindow. Это не имеет ничего общего со строгим режимом. Конечно, сейчас мы его так не используем, но иногда это случайно так пишется, и это нужно понимать.

фактическиthisСуществует много сценариев использования, таких как объектobjectсерединаgetter,setterизthis,new Function(),eval. Но если вы освоите вышеперечисленное и проанализируете остальные, вы, естественно, решитесь. Чаще используются обычные вызовы функций, вызовы объектных функций,newпередача,call、apply、bindвызов, вызов функции стрелки. Так каковы их приоритеты?

приоритет

И функция стрелкиthisявляется обычной функцией верхнего уровняthisили глобальный объект (в браузерах этоwindow), поэтому исключено, не считается приоритетом.

var name = 'window';
var person = {
    name: 'person',
}
var doSth = function(){
    console.log(this.name);
    return function(){
        console.log('return:', this.name);
    }
}
var Student = {
    name: '若川',
    doSth: doSth,
}
// 普通函数调用
doSth(); // window
// 对象上的函数调用
Student.doSth(); // '若川'
// call、apply 调用
Student.doSth.call(person); // 'person'
new Student.doSth.call(person);

Вы только представьте, если бы это былоStudent.doSth.call(person)Если выполнить сначала, тоnewВыполнить функцию. Нет проблем. Однако на самом деле этот код ошибочен.приоритет операторадаnewОн ниже номера точки, поэтому выполняетсяnew (Student.doSth.call)(person)а такжеFunction.prototype.call, хотя функция (apply,bindЭто также функция), как функции стрелки, не может использоватьnewпередача. Так что это неправильно.

Uncaught TypeError: Student.doSth.call is not a constructor

Это потому, что внутри функции есть два разных метода:[[Call]]а также[[Constructor]]. При использовании обычного вызова функции[[Call]]будет казнен. При вызове с конструктором[[Constructor]]будет казнен.call,apply,bindа внутри стрелочной функции нет[[Constructor]]метод.

Из приведенного выше примера видно, что обычные вызовы функций имеют самый низкий приоритет, за ними следуют функции над объектами.call(apply、bind)метод вызова иnewПриоритет вызывающего метода сравнивается в «JavaScript, которого вы не знаете».bindа такжеnewquoted.mdnизbindизployfillвыполнить,newФункция после привязки игнорируется при вызовеbindПервый параметр привязки (mdnНа самом деле есть еще некоторые проблемы в реализации .Заинтересованные читатели могут прочитать мои предыдущие статьи:Интервьюер спросил: Можно ли это смоделировать?JSизbindметод), проиллюстрироватьnewВызов имеет наивысший приоритет. Так что их приоритетnewпозвонить >call、apply、bindВызовы > Вызовы функций для объектов > Обычные вызовы функций.

Суммировать

Если вы хотите определить значение запущенной функцииthisДля привязки нужно найти место прямого вызова этой функции. после нахождения Следующие четыре правила могут быть применены для оценкиthisобъект привязки.

  1. newвызов: привязать к вновь созданному объекту, примечание: показатьreturnФункция или объект, возвращаемое значение которого не является вновь созданным объектом, а явно возвращенной функцией или объектом.
  2. callилиapply( илиbind) вызов: в строгом режиме выполнить привязку к указанному первому параметру. В нестрогом режимеnullа такжеundefined, указывая на глобальный объект (в браузереwindow), остальные значения указывают наnew Object()Завернутый объект.
  3. Вызов функции для объекта: привязка к этому объекту.
  4. Обычный вызов функции: привязать в строгом режиме кundefined, в противном случае привязанный к глобальному объекту.

ES6Стрелочные функции в : Четыре стандартных правила привязки выше не используются, но определяются в соответствии с текущей лексической областьюthisВ частности, стрелочная функция наследует внешнюю функцию, а привязка вызова this (независимо от того, к чему привязано this), если внешней функции нет, она привязывается к глобальному объекту (в браузере этоwindow). На самом деле это иES6в предыдущем кодеself = thisМеханизм тот же.

DOMФункция события: обычно указывает на связанное событиеDOMэлементы, но в некоторых случаях связаны с глобальным объектом (например,IE6~IE8изattachEvent).

Важно отметить, что некоторые вызовы могут непреднамеренно использовать обычные правила связывания функций. Если вы хотите "безопаснее" игнорироватьthisгалстук Конечно, вы можете использовать такой объект, как ø = Object.create(null), чтобы защитить глобальный объект.

Осмотр интервьюераthisточка для расследованияnew、call、apply、bind, стрелочные функции и т. д. Это распространяется на область действия, замыкания, цепочки прототипов, наследование, строгий режим и многое другое. Вот почему интервьюеры так любят это.

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

экзаменационные вопросы

thisЭкзаменационные вопросы по указыванию часто сочетаются с некоторыми операторами для изучения. После прочтения этой статьи вы можете захотеть пройти тест на следующие два вопроса интервью.Little Canghai: вопрос на собеседовании по интерфейсу JS, который часто презирают
Из этих двух наборов вопросов заново поймите JS this, объем, закрытие и объект.

Расширенное чтение

JavaScript Rollup вы не знаете
Ю Ю: Углубленная интерпретация JavaScript из спецификации ECMAScript.
Эта волна может дать отпор: продвинутые основы интерфейса (5): всесторонняя интерпретация этого

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

Изучите общую архитектуру исходного кода 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].