Зачем изучать это ключевое слово
-
Интервью спросят! Всегда найдутся интервьюеры, которым нравится спрашивать вас о фрагменте кода, который невозможно написать. Посмотрите на классический и старый вопрос для интервью (после того, как вы закончите эту статью, в конце вас будет ждать более сложный вопрос для интервью!)
код показывает, как показано ниже:
var a = 5; var obj = { a : 10, foo: function(){ console.log(this.a) } } var bar = obj.foo obj.foo() bar()
-
Когда я читал исходный код lib/events событий, я обнаружил, что ключевое слово call используется много раз, кажется, что необходимо понимать все, что связано с этим и вызовом.
Часть кода написана так
// 场景1: function EventEmitter() { EventEmitter.init.call(this); } // 场景2: return this.listener.call(this.target); // 场景3: return listenerCount.call(emitter, type);
-
Неправильное использование стрелочных функций сообщает об ошибке. При инкапсуляции Sequelize, инфраструктуры отображения ORM Node.js, инкапсулируется отношение ассоциации таблиц. Из-за использования стрелочных функций контекст чтения изменяется. Вместо желаемой информации о модели он указывает на глобальное.
-
Ключевое слово call по-прежнему широко используется в процессе написания кода.Иногда мы часто используем ключевое слово call для указания контекста выполнения функции, а иногда также используем ключевое слово call для реализации наследования.
Пример кода выглядит следующим образом:
var person = {
"name": "koala"
};
function changeJob(company, work) {
this.company = company;
this.work = work;
};
changeJob.call(person, '百度', '程序员');
console.log(person.work); // '程序员'
Обзорная карта статьи
Об авторе: koala, сосредоточив внимание на совместном использовании полного стека технологий Node.js, от JavaScript до Node.js, до серверной базы данных, я желаю вам стать отличным старшим инженером Node.js. [Руководство по развитию программиста] Автор, блог Github с открытым исходным кодомGitHub.com/koala-co Nth…
вызов функции
В JS (ES5) есть три формы вызова функций:
func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2) // 这里先不讲 apply
Многие новички использовали только первые два случая и считают, что первые два лучше, чем третий. Еще несколько дней назад я хотел систематически просматривать это ключевое слово, находить различную информацию, связанную с этим, и видел обсуждение этого вопроса в Zhihu. Говорят, что третья форма — это нормальная форма вызова.
func.call(context,p1,p2)
Два других являются синтаксическим сахаром и могут быть эквивалентно изменены наcall
форма.func(p1, p2)等价于 func.call(undefined, p1, p2);
obj.child.method(p1, p2) 等价于 obj.child.method.call(obj.child, p1, p2);
Глядя на это таким образом, наш вызов функции имеет только одну форму:
func.call(context,p1,p2)
В это время, знаете ли вы, что это такое, контекст выше. Вернемся к вопросу интервью, который я упомянул в начале.
var a = 5;
var obj = {
a : 10,
foo: function(){
console.log(this.a)
}
}
var bar = obj.foo
obj.foo()
bar()
- Форма obj.foo(), преобразованная в вызов, такова: obj.foo.call(obj)
так что это указывает на obj
- Форма bar(), преобразованная в вызов, bar.call() Поскольку контекст не передается, это не определено.Если он находится в браузере, он, наконец, даст вам объект этого окна по умолчанию. При работе в среде Node.js это -- объект глобуса. Результат равен 5 в браузере и не определен в среде Node.js.
Описание этого ключевого слова, указывающего на глобальную среду Node.js (вы можете этого не знать)
Почему значение может быть напрямую выведено в браузере или интерфейсной среде, но вывод в среде Node.jsundefined
.
Взгляните на этот код, и вы, возможно, поймете.
(function(exports, require, module, __filename, __dirname) {
{
// 模块的代码
// 所以那整个代码应该在这里吧
var a = 10;
function A(){
a = 5;
console.log(a);
console.log(this.a);
}
// const haha = new A();
A();
}
});
Давайте поговорим о том, что происходит, когда код модуля js запускается в среде Node.js.Node.js будет использовать оболочку кода для инкапсуляции кода перед его выполнением, например, как показано ниже:
(function(exports, require, module, __filename, __dirname) {
{
// 模块的代码
// 所以那整个代码应该在这里吧
}
});
Вывод этого кода в среде Node.js:5,undefined
Это понятно.
Это здесь является привязкой по умолчанию к глобалу.Когда this.a выводится, глобал должен указывать на самый внешний слой замыкания. Таким образом, результат вывода не определен.
это ключевое слово в синтаксисе []
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 这里面的 this 又是什么呢?
мы можем поставить обр0Представьте его как arr.0(), хотя синтаксис последнего неверен, но форма соответствует obj.child.method(p1, p2) в коде преобразования, поэтому его можно успешно преобразовать:
arr[0]()
假想为 arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了
этот обязательный принцип
привязка по умолчанию
Привязка по умолчанию заключается в том, что при независимом вызове функции ссылка на функцию вызывается без каких-либо изменений, в нестрогом режиме это указывает на глобальный объект (в браузере он указывает на Window, а среда Node.js Global).В строгом режиме это Binding to undefined, строгий режим не позволяет this указывать на глобальный объект.
var a = 'hello'
var obj = {
a: 'koala',
foo: function() {
console.log(this.a)
}
}
var bar = obj.foo
bar() // 浏览器中输出: "hello"
этот код,bar()
Это привязка по умолчанию, при вызове функции перед ней нет вызова модификации, и можно использовать и предыдущий.call
Форма вызова функции понятна, поэтому результат выводаhello
.
Другой случай привязки по умолчанию
Передайте функцию в качестве параметра функции, например.setTimeOut
иsetInterval
и т. д., в функции, переданной в этих функцияхthis
Указывает в нестрогом режиме на глобальный объект.
пример:
var name = 'koala';
var person = {
name: '程序员成长指北',
sayHi: sayHi
}
function sayHi(){
setTimeout(function(){
console.log('Hello,', this.name);
})
}
person.sayHi();
setTimeout(function(){
person.sayHi();
},200);
// 输出结果 Hello,koala
// 输出结果 Hello,koala
неявное связывание
Основные критерии для оценки этой неявной привязки: вызывается ли функция в контексте, когда функция вызывается, или объект вызывает функцию.
пример:
var a = 'koala'
var obj = {
a: '程序员成长指北',
foo: function() {
console.log(this.a)
}
}
obj.foo() // 浏览器中输出: "程序员成长指北"
Метод foo вызывается как свойство объекта, поэтому при выполнении метода foo это указывает на объект obj.
Другой случай неявного связывания
Когда есть несколько слоев объектов, вложенных для вызова функции, например对象.对象.函数
, это указывает на последний слой объектов.
пример:
function sayHi(){
console.log('Hello,', this.name);
}
var person2 = {
name: '程序员成长指北',
sayHi: sayHi
}
var person1 = {
name: 'koala',
friend: person2
}
person1.friend.sayHi();
// 输出结果为 Hello, 程序员成长指北
Прочитав этот пример, вы также понимаете ситуацию с неявным вызовом.
явная привязка
Явная привязка, указатель функции this может быть изменен через вызов функции apply bind. Методы вызова и применения являются методами, смонтированными в прототипе функции, и могут использоваться всеми функциями.
Разница между вызовом и применением
- Первый параметр вызова и применения привязан к этому телу функции, если
不传参数
,Напримерfun.call()
, нестрогий режим, по умолчанию привязан к глобальному объекту - Функция вызова получает список параметров, а функция применения — массив параметров.
unc.call(thisArg, arg1, arg2, ...) // call 用法
func.apply(thisArg, [arg1, arg2, ...]) // apply 用法
См. пример кода:
var person = {
"name": "koala"
};
function changeJob(company, work) {
this.company = company;
this.work = work;
};
changeJob.call(person, '百度', '程序员');
console.log(person.work); // '程序员'
changeJob.apply(person, ['百度', '测试']);
console.log(person.work); // '测试'
Примечания о вызове и применении
Когда эти два метода вызываются, если мы передаем числа или строки, эти два метода преобразуют входящие параметры в типы объектов.
пример:
var number = 1, string = '程序员成长指北';
function getThisType () {
var number = 3;
console.log('this指向内容',this);
console.log(typeof this);
}
getThisType.call(number);
getThisType.apply(string);
// 输出结果
// this指向内容 [Number: 1]
// object
// this指向内容 [String: '程序员成长指北']
// object
функция привязки
метод привязки Будет создана новая функция. Когда эта новая функция вызывается, первым аргументом bind() будет this среды выполнения, а следующая последовательность аргументов будет передана в качестве ее аргументов перед переданными аргументами. (Содержание определения взято из MDN)
func.bind(thisArg[, arg1[, arg2[, ...]]]) // bind 用法
пример:
var publicAccounts = {
name: '程序员成长指北',
author: 'koala',
subscribe: function(subscriber) {
console.log(subscriber + this.name)
}
}
publicAccounts.subscribe('小红') // 输出结果: "小红 程序员成长指北"
var subscribe1 = publicAccounts.subscribe.bind({ name: 'Node成长指北', author: '考拉' }, '小明 ')
subscribe1() // 输出结果: "小明 Node成长指北"
новая привязка
Что происходит, когда функция вызывается с помощью new:
- Создать пустой объект
- пустой объектprotoуказатель на прототип исходного объекта
执行构造函数中的代码
- вернуть этот новый объект
пример:
function study(name){
this.name = name;
}
var studyDay = new study('koala');
console.log(studyDay);
console.log('Hello,', studyDay.name);
// 输出结果
// study { name: 'koala' }
// hello,koala
существуетnew study('koala')
Когда он изменит указатель this, будетthis指向指定到了studyDay对象
.
Примечание. Если вы создаете новый объект, а конструктор не передает значение, свойство в новом объекте не будет иметь значения, но новый объект будет иметь это свойство.
Вручную реализовать код создания нового объекта (несколько реализаций)
function New(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype;
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1));
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
var obj = New(A, 1, 2);
// equals to
var obj = new A(1, 2);
этот обязательный приоритет
Четыре обязательных правила для этого представлены выше, но иногда фрагмент кода применяет несколько правил одновременно.Как это должно указывать на это в данный момент? На самом деле они тоже имеют последовательный порядок, конкретные правила таковы:
новая привязка > явная привязка > неявная привязка > привязка по умолчанию
это в стрелочных функциях
стрелочная функция
Прежде чем говорить об этом в стрелочных функциях, давайте поговорим о стрелочных функциях.
определение
MDN: выражения функции стрелки имеют более короткий синтаксис, чем выражения функции, и не связывают свои собственные this, arguments, super или new.target. Эти функциональные выражения лучше всего использовать для функций, не являющихся методами, и их нельзя использовать в качестве конструкторов.
- В стрелочных функциях нет аргументов
Обычные функции могут напрямую получать свойство arguments, но если вы используете свойство arguments в стрелочной функции, вы получаете свойство arguments внешней функции стрелочной функции.
пример:
function constant() {
return () => arguments[0]
}
let result = constant(1);
console.log(result()); // 1
Что, если мы просто хотим получить доступ к параметрам стрелочной функции?
Вы можете получить доступ к параметрам как к именованным параметрам ES6 или остальным параметрам.
let nums = (...nums) => nums;
- Стрелочные функции не имеют конструктора
Стрелочные функции отличаются от обычных функций.Стрелочные функции не имеют конструктора.Поскольку конструктора нет, их нельзя вызвать с помощью new.Если мы вызовем стрелочную функцию напрямую с помощью new, будет сообщено об ошибке.
пример:
let fun = ()=>{}
let funNew = new fun();
// 报错内容 TypeError: fun is not a constructor
- Стрелочные функции не имеют прототипа
Прототип-прототип является свойством функций, но не стрелочных функций.
пример:
let fun = ()=>{}
console.loh(fun.prototype); // undefined
- В стрелочных функциях нет super
Как было сказано выше, прототипа нет, даже прототипа.Естественно, к свойствам прототипа нельзя обратиться через super, поэтому у стрелочной функции тоже нет super, а вот так, аргументы, и new.target, эти значения определяются ближайшей нестрелкой во внешнем слое, решает функция.
箭头函数中没有自己的this
У стрелочной функции нет собственного this.Это в стрелочной функции нельзя изменить с помощью call(), apply(), bind() и этих методов.Это в стрелочной функции напрямую указывает на调用函数的 上一层运行时
.
let a = 'kaola'
let obj = {
a: '程序员成长指北',
foo: () => {
console.log(this.a)
}
}
obj.foo() // 输出结果: "koala"
Прочитав результаты вывода, боюсь, что у всех возникнут сомнения или анализ, в стрелочной функции, о которой я упоминал ранее, это прямо указывает на调用函数的上一层运行时
, этот кодobj.foo
При вызове, если функция стрелки не используется, это должно указывать на OBJ, но если используется функция стрелки, она будет указывать на весь мир, поэтому результат выводаkoala
.
самовыполняющаяся функция
Что такое самовыполняющаяся функция? Самовыполняющаяся функция будет выполняться автоматически после того, как мы сможем только определить ее в коде, не вызывая ее. В процессе разработки есть время протестировать небольшой фрагмент кода, чтобы сообщить об ошибках. Пример кода выглядит следующим образом:
(function(){
console.log('程序员成长指北')
})()
или
(function(){
console.log('程序员成长指北')
}())
Но если вы используете стрелочные функции для упрощения, вы можете использовать только первый случай. Использование упрощения во втором случае сообщит об ошибке.
(() => {
console.log('程序员成长指北')
})()
этот сценарий приложения
Сценарий применения, собственно, то, почему я написал эту статью в начале, и повторю еще раз.
- Интервьюер прошел тест!
- Глядя на исходный код, я всегда его вижу, и иногда хочется подтвердить текущий контекст. Почему так много используется исходный код, вы можете подумать над этим вопросом.
- Мы также используем его при написании кода, и часто есть контекст, в котором вызов используется для указания на объект или для реализации наследования и т. д.
После школьной практики
Узнав об этом, вы обнаружили, что вопрос интервью в начале был немного простым, и он больше не может удовлетворить ваш текущий запас знаний по этому ключевому слову. Хорошо, давайте перейдем к более сложному вопросу интервью.
код показывает, как показано ниже:
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
}
};
obj.method(fn, 1);//输出是什么?
Вывод этого кода:10,2
Если вы внимательно читали статью, то должны быть в состоянии ответить правильно. Каждая деталь описана в статье. Я не буду разбирать это здесь. Если вы не поняли, вы можете прочитать статью еще раз, или добавить в друзья прямо и давайте обсудим это вместе.Каола-это люди, которые готовы поделиться, с нетерпением ждем прогресса вместе с вами.
Отказ от ответственности: Пожалуйста, свяжитесь со мной, если вы перепечатаете в любой форме, и спасибо за ваши указания и предложения, если у вас есть какие-либо вопросы.
Справочная статья
- Объяснение этого ключевого слова в MDNdeveloper.Mozilla.org/this-cn/docs/…
- Обсуждение этого в Zhihu:Ууху. Call.com/question/19…
- Содержание стрелочных функций в книгах Руана Ифэна по ES6
- Книга "JavaScript, которого вы не знаете"
Присоединяйтесь к нам, чтобы учиться вместе!