предисловие
В этой статье подробно объясняется Байтовые вопросы на собеседовании
Кстати, шаг за шагом полностью решить проблему этого указания на приоритет в js.⛹️♂️⛹️♂️
Проблема этого в js должна быть темой, которая обсуждается давно, в Nuggets тоже много статей на эту тему. Однако, может быть, статьи, которые я видел раньше, мне не очень подходят, и каждый раз, когда я их читаю, я все еще не понимаю и не имею особых зацепок. Мне повезло, что несколько дней назад мой старый старший…Мэн братПосле обмена кажется, что у меня появилось более глубокое понимание этого вопроса, поэтому я написал статью, чтобы обобщить его. 🌈
只要你仔细认真看完这篇文章,不管你是 js 新手、还是大佬,我保证你一定会有收获的!如果一丢丢收获都没有,你可以揍我!️👀
Без лишних слов, давайте сначала поговорим о теме
- Пожалуйста, реализуйте это вручную в ES5
Functionпрототипbind(т.е. написанный от руки myBind в следующем блоке кода), чтобы следующая программа наконец смогла вывести'success'.
function Animal(name, color) {
this.name = name;
this.color = color;
}
Animal.prototype.say = function () {
return `I'm a ${this.color} ${this.name}`;
};
const Cat = Animal.myBind(null, 'cat');
const cat = new Cat('white');
if (cat.say() === 'I\'m a white cat' &&
cat instanceof Cat && cat instanceof Animal) {
console.log('success');
}
先来看看解题需要了解的一些问题 慢慢来 不要慌张🌈
связанная информация
Чтобы разобраться в этом вопросе, необходимо иметь некоторые знания
Во-первых, смысл ЭТОГО в JS
- В ES5 указание this всегда является принципом: указание this не определяется при его создании.это всегда указывает на объект, который последний раз вызывал его.
Вот несколько примеров, демонстрирующих вышеизложенное
one
var name = "globalName";
function a() {
var name = "jingjing";
console.log(this.name)
}
a(); //globalName
По принципу чуть выше:это всегда указывает на объект, который последний раз вызывал егоможет получить ответ. Где мы видим последний звонок к? В последней строке кодаa(); объект, который не вызывается перед ним, то он является глобальным объектом по умолчаниюwindow,такconsole.log(this.name)это становитсяconsole.log(window.name), вывод результатаglobalName(👉В нестрогом режиме 👈).
two
var name = "globalName";
var a = {
name: "jingjing",
jing: function () {
console.log(this.name); // jingjing
}
}
window.a.jing();
Я собираюсь повторить вышеприведенную фразу снова 😁.это всегда указывает на объект, который последний раз вызывал егоможно получить ответ. Давайте посмотрим на последний звонокjing()Где место для функции? или функцияjing()этот слева.Какой предмет находится слева от ? очевидно, объект a, поэтомуconsole.log(this.name)это становитсяconsole.log(a.name), вывод результатаjingjing.
three
var name = "globalName";
var a = {
name: "jingjing",
jing: function () {
console.log(this.name); // globalName
}
}
var hao = a.jing
hao();
🎈 Здесь мы присваиваем метод jing объекта a переменной hao, но будьте внимательны! ! ! 🔍 Этот шаг не вызывает метод исполнения цзин! . последняя строка кодаhao()только бытьwindowвызов выполненjing()метод. такconsole.log(this.name)это становитсяconsole.log(window.name), вывод результатаglobalName. Возьмем еще раз этот принцип:это всегда указывает на объект, который последний раз вызывал его. 🌈🌈🌈
2. Четыре обязательных правила для этого
В JavaScript есть четыре правила привязки, на которые указывает this:
- Привязка по умолчанию (в нестрогом режиме это указывает на
window, в строгом режиме это указывает наundefined. ) - Неявная привязка (если есть объект, вызывающий ее при вызове функции, то это будет неявно привязано к этому объекту)
- Явная привязка (функция через
call(),apply(),bind()Вызывается, это указывает на связанный объект. ) - новая привязка (функция
newпередача,thisрежиссерnewНовый построенный объект. )
Первые два были поняты выше, а теперь давайте сосредоточимся на последних двух.
явная привязка
Этот метод привязки заключается в использованииFunction.prototypeтри метода вcall(),apply(),а такжеbind().这三个函数,都可以改变函数的 this 指向到指定的对象,不同之处在于:
-
call()а такжеapply()обевыполнить функцию немедленно, но они принимают параметры в разных формах, например:
call(this, arg1, arg2, ...)
apply(this, [arg1, arg2, ...])
- а также
bind()являетсявозвращает новую функцию-оболочкуНе сразу.bind()Будет создана новая функция. Когда эта новая функция вызывается,bind()Первый аргумент будет использоваться в качестве времени выполнения.this, следующая последовательность аргументов будет передана в качестве его аргументов перед переданными аргументами.
bind(this, arg1, arg2, ...)
новая привязка
Когда функция вызывается с new или происходит вызов конструктора, автоматически выполняются следующие операции.
- 1. Создайте (или сконструируйте) совершенно новый объект.
- 2. Этот новый объект будет связан с [[Prototype]].
- 3. Этот новый объект будет привязан к этому вызову функции.
- 4. Если функция не возвращает другой объект, то вызов функции в новом выражении автоматически возвращает новый объект.
В JavaScript оператор new не похож на другие объектно-ориентированные языки, а представляет собой эмулируемый механизм. В JavaScript все функции могут вызываться с помощью new. В настоящее время эта функция обычно называется «конструктором». На самом деле так называемого «конструктора» не существует. Более точно следует понимать «конструктор» функция "режим вызова".
Вышеприведенное о новой привязке исходит из неизвестных вам правил привязки js rollup 2.2.
3. Приоритет обязательных правил
новая привязка > явная привязка > неявная привязка > привязка по умолчанию
Вывод такой же, как и выше, и ниже приведены некоторые примеры, подтверждающие этот вывод.
毫无疑问,默认绑定的优先级是四条规则中最低的,所以我们可以先不考虑它。
one
function jing() {
console.log(this.a);
}
var obj1 = {
a: 10,
foo: jing
};
var obj2 = {
a: 20,
foo: jing
};
obj1.foo(); //10
obj2.foo(); //20
obj1.foo.call(obj2); //20
obj2.foo.call(obj1); //10
Из этого текущего результата видно, что последние две строки приведенного выше блока кода изменили точку этого с помощью метода call(). Таким образом, вы можете получитьЯвное связывание > Неявное связываниеэтот вывод.
two
function jing() {
this.a = 'hao';
}
let obj = {
a: 'jing'
};
// 1、bind
const Bar = jing.bind(obj);
// 2、new
const bar = new Bar();
console.log(obj.a, '--', bar.a) //jing -- hao
Третья-последняя строка вышеуказанного блока кода проходитbind()метод измененthisуказывает наobj, из вышеперечисленногоbar.aРезультат распечаткиhaoВидно, что предпоследняя строка кода измениласьthisнаправлениеjing(), так что вы можете получитьновая привязка > явная привязка.
Итак, в итоге можно сделать вывод, что:новая привязка > явная привязка > неявная привязка > привязка по умолчанию
В-четвертых, напишите упрощенную версию bind().
код показывает, как показано ниже:
Function.prototype.myBind = function (thisObj, ...arg1) {
// 1、这里 ...arg1 是第一次传的参数
let fn = this;
// 这里用 fn 记下调用对象
function jingbind(...arg2) {
// 2、这里 ...arg2 是下一次传的参数
const args = arg1.concat(arg2);
// 谁调用 bind,最终拼好的参数就传给谁
return fn.apply(thisObj, args);
}
return jingbind;
// bind() 返回一个未执行的函数
}
с рукописнымmyBind(), давайте напишем еще один тестовый код, чтобы попробовать эффект:
function sum(a, b, c) {
return a + b + c;
}
const sum10 = sum.myBind(null, 10);
let jing = sum10(20, 30);
console.log(jing) //60
🙌🙌После тестирования успешно выводится правильный результат. Теперь мы можем попробовать то, что мы только что реализовали.myBind()Может ли метод решить вопрос интервью, поставленный в верхней части статьи! Интересно думать об этом! ! 🙋♂️🙋♂️
процесс решения проблем
Поместите вышеуказанный метод вместе с данной темой и попробуйте его.
Function.prototype.myBind = function (thisObj, ...arg1) {
if (typeof this !== "function") {
throw new TypeError("not a function");
}
// 1、这里 ...arg1 是第一次传的参数
let fn = this;
// 这里用 fn 记下调用对象
function jingbind(...arg2) {
// 2、这里 ...arg2 是下一次传的参数
const args = arg1.concat(arg2);
// 谁调用 bind,最终拼好的参数就传给谁
return fn.apply(thisObj, args);
}
return jingbind;
// bind() 返回一个未执行的函数
}
function Animal(name, color) {
this.name = name;
this.color = color;
}
Animal.prototype.say = function () {
return `I'm a ${this.color} ${this.name}`;
};
const Cat = Animal.myBind(null, 'cat');
const cat = new Cat('white');
console.log(cat.say()) //这句代码是作者解题调试加上去的
if (cat.say() === 'I\'m a white cat' &&
cat instanceof Cat && cat instanceof Animal) {
console.log('success');
}
Жаль, это нормально, это неправильно. Скриншот сообщения об ошибке выглядит следующим образом:
- Сообщение об ошибке показывает, что
cat.say() is not a function, то почему это не метод? - Найдем это в коде
cat.say(), шаг за шагом, чтобы наверстать упущенное. - это
catОткуда это? ОтCatначальствоnewПример, который выходит, то этоCatОткуда это? КAnimal.myBindсгенерировано, вы позвонилиmyBind()Я вернул его вам. ЭтоmyBind()Что оно вернуло? то, что он возвращаетjingbind(). Так что в итоге мы можем получитьCat === jingbind(), который можно получитьcat === new jingbind(). - Затем мы обнаружили, что написали это
jingbind()В функции нет определенияsay()кстати, этоsay()Метод определенAnimal.prototypeнад. - То есть изначально
Animal.prototypeEстьsay()метод, но после того, как мы напишемmyBind()После обработки метода поместитеAnimal.prototypeпотерянный. - Итак, мы должны добавить к этому, так как? Изменено
myBind()код показывает, как показано ниже:
Function.prototype.myBind = function (thisObj, ...arg1) {
if (typeof this !== "function") {
throw new TypeError("not a function");
}
// 1、这里 ...arg1 是第一次传的参数
let fn = this;
// 这里用 fn 记下调用对象
function jingbind(...arg2) {
// 2、这里 ...arg2 是下一次传的参数
const args = arg1.concat(arg2);
// 谁调用 bind,最终拼好的参数就传给谁
return fn.apply(thisObj, args);
}
jingbind.prototype = fn.prototype; //只添加了这一行代码
return jingbind;
// bind() 返回一个未执行的函数
}
Попробуйте снова
😎😎😎
- Код не сообщает об ошибке, указывающей на добавление прототипа.
- Но этот вывод показывает, что мы только что успешно добавили прототип и обнаружили, что не передаем параметры нормально. 🤕🤕🤕
- потому что это не связано с кошкой
Это включает в себя приоритет этого правила привязки в js, упомянутого ранее. мы написалиmyBind()В функции нет определения приоритета(Другими словами, нет соответствующей привязки this для разных правил привязки this).
Сделать myBind() идеальным
МыmyBind()Внесите некоторые изменения в метод следующим образом:
Function.prototype.myBind = function (thisObj, ...arg1) {
if (typeof this !== "function") {
throw new TypeError("not a function");
}
// 1、这里 ...arg1 是第一次传的参数
let fn = this;
// 这里用 fn 记下调用对象
function jingbind(...arg2) {
// 2、这里 ...arg2 是下一次传的参数
const args = arg1.concat(arg2);
// 谁调用 bind,最终拼好的参数就传给谁
let isjing = this instanceof jingbind; //判断是否是 new 调用
return fn.apply(isjing ? this : thisObj, args);
}
jingbind.prototype = fn.prototype;
return jingbind;
// bind() 返回一个未执行的函数
}
-
instanceofразумеется - мы используем
instanceofЧтобы определить, вызывается ли он новым, если он вызывается новым, мы должны привязать это к экземпляру. - Если он не был вызван new , мы просто привязываем его к
myBind()Первый параметр функции -thisObj, мы должны получить желаемый результат, если поступим с этим так 🤐🤐
再来测试一下🥱
В итоге мы придумали этот метод. 💦💦💦
наконец
- Этот вопрос исходит от моего старого старшегоМэн братВопросы для интервью для тех, кто не является автором (все еще 🥦💪).
- Мой брат Мэн сказал: «Я тщательно разобрался с этой проблемой, и связанные с этим вопросы js почти понятны.
- Все вышеперечисленные точки зрения написаны автором, и если вы этого не понимаете, вы также можете прочитать краткое содержание книги.
- Автор - студент, который только начал заниматься фронтендом, поэтому в статье могут быть какие-то ошибки, если начальник это увидит и укажет на исправление, чтобы у Дабая была еще одна возможность научиться, то ему настоящий босс😜
Автор создал веб-сайт блога, готовый начать с основ, постоянно обновлять, создавать полную систему знаний и готовиться к будущим интервью. Если вы только начинаете, то можете прийти и посмотреть, если вам это нужно🙋♂️🙋♂️
последний из последних
Если у вас есть какие-либо вопросы, добро пожаловать, чтобы добавить автора WeChat для обмена и обучения (большой брат игнорирует 👀)