Автор: Дмитрий Павлютин Переводчик: Front-end Xiaozhi Источник: дмитрипавлутин
Ставь лайк и смотри, поиск в WeChat【Переезд в мир】Обратите внимание на этого человека, который не имеет большого фабричного прошлого, но имеет восходящий и позитивный настрой. эта статья
GitHub
GitHub.com/QQ449245884…Он был включен, статьи были классифицированы, и многие мои документы и учебные материалы были систематизированы.
Все говорили, что нет проекта для написания резюме, поэтому я помог вам найти проект, и это было с бонусом.【Учебник по строительству】.
1. Тайна этого
Много раз в JSthis
Нашим новичкам легко запутаться.this
Функция очень мощная, но требуется некоторое усилие, чтобы понять ее медленно.
Для Java, PHP или других стандартных языковthis
Представляет экземпляр текущего объекта в методе класса. в большинстве случаев,this
Его нельзя использовать вне метода, чтобы сравнение было менее запутанным.
В J ситуация иная:this
Указывает текущий контекст выполнения функции.Вызовы функций в JS в основном включают следующие методы:
-
вызов функции:
alert('Hello World!')
-
Вызов метода:
console.log('Hello World!')
-
Конструктор:
new RegExp('\\d')
-
Неявный вызов:
alert.call(undefined, 'Hello World!')
Каждый тип вызова определяет контекст по-своему, поэтому легко может возникнуть путаница.
Кроме того, строгий режим влияет на контекст выполнения.
пониматьthis
Ключ в том, чтобы иметь четкое представление о вызове функции и о том, как он влияет на контекст.
В этой статье в основном объясняется, как вызывается функция и как она влияет наthis
и объясняет распространенные ошибки контекстов выполнения.
Прежде чем мы начнем, знайте несколько терминов:
Вызывающая функция выполняет код, создавший тело функции, или просто вызывает функцию. Например, вызов функции parseInt — это parseInt('15').
-
вызов функции: выполнить код, составляющий тело функции: например,
parseInt
Вызов функцииparseInt('15')
. -
контекст вызова:Ссылаться на
this
Значение внутри тела функции. Например,map.set('key', 'value')
Контекст вызоваmap
. -
объем функции: это набор переменных, объектов и функций, доступных в теле функции.
2. Вызов функции
Когда выражение представляет собой функцию, за которой следует(
, некоторые аргументы, разделенные запятыми, и)
, вызов функции выполняется, например.parseInt('18')
.
Выражение вызова функции не может быть вызовом атрибута, напримерobj.myFunc()
, который должен создать вызов метода. Другой пример[1,5].join(',')
Не вызов функции, а вызов метода,Это различие нужно помнить, оно очень важно..
Простой пример вызова функции:
function hello(name) {
return 'Hello ' + name + '!';
}
// 函数调用
const message = hello('World');
console.log(message); // => 'Hello World!'
hello('World')
это вызов функции:hello
Выражение эквивалентно функции, за которой следует пара круглых скобок и'World'
параметр.
Более продвинутым примером может бытьIIFE(сразу же называется функциональным выражением)
const message = (function(name) {
return 'Hello ' + name + '!';
})('World');
console.log(message) // => 'Hello World!'
IIFEТакже вызов функции: первая пара скобок(function(name) {...})
это выражение, результатом которого является объект функции, за которым следует пара круглых скобок, аргументы которых“World”
.
2.1 this в вызовах функций
это глобальный объект в вызовах функций
Локальные объекты определяются средой выполнения. В браузереthis
даwindow
объект.
При вызове функции контекстом выполнения является глобальный объект.
Давайте посмотрим, какой, черт возьми, контекст в следующей функции:
function sum(a, b) {
console.log(this === window); // => true
this.myNumber = 20; // 将'myNumber'属性添加到全局对象
return a + b;
}
// sum() is invoked as a function
// sum() 中的 `this` 是一个全局对象(window)
sum(15, 16); // => 31
window.myNumber; // => 20
вызовsum(15,16)
, JS автоматическиthis
Установите глобальный объект, который в браузереwindow
.
когдаthis
Используется вне области действия любой функции (самая верхняя область: глобальный контекст выполнения),this
выражатьwindow
объект
console.log(this === window); // => true
this.myString = 'Hello World!';
console.log(window.myString); // => 'Hello World!'
<!-- In an html file -->
<script type="text/javascript">
console.log(this === window); // => true
</script>
2.2 Как это выглядит при вызове функции в строгом режиме
this
в вызове функции в строгом режимеundefined
Строгий режим был введен в ECMAScript 5.1 и обеспечивает лучшую безопасность и более строгую проверку ошибок.
Чтобы включить строгий режим, заголовок функции пишетuse strict
Вот и все.
При включении строгий режим влияет на контекст выполнения,this
При обычном вызове функции значение равноundefined
. с вышеуказанным2.1
Вместо этого контекст выполнения больше не является глобальным объектом.
Пример вызова функции в строгом режиме:
function multiply(a, b) {
'use strict'; // 启用严格模式
console.log(this === undefined); // => true
return a * b;
}
multiply(2, 5); // => 10
когдаmultiply(2,5)
При вызове как функцииthis
даundefined
.
Строгий режим действует не только в текущей области видимости, но и во внутренних областях видимости (для всех функций, объявленных внутри):
function execute() {
'use strict'; // 开启严格模式
function concat(str1, str2) {
// 严格模式仍然有效
console.log(this === undefined); // => true
return str1 + str2;
}
// concat() 在严格模式下作为函数调用
// this in concat() is undefined
concat('Hello', ' World!'); // => "Hello World!"
}
execute();
'use strict'
вставляется в начало выполнения, включая строгий режим в своей области. потому что функцияconcat
объявляется в области выполнения, поэтому он наследует строгий режим.
Один файл JS может содержать строгие и нестрогие режимы. Следовательно, в одном скрипте для одного и того же типа вызова может быть разное контекстуальное поведение:
function nonStrictSum(a, b) {
// 非严格模式
console.log(this === window); // => true
return a + b;
}
function strictSum(a, b) {
'use strict';
// 启用严格模式
console.log(this === undefined); // => true
return a + b;
}
nonStrictSum(5, 6); // => 11
strictSum(8, 12); // => 20
2.3 Подводные камни:this
когда внутри функции
Распространенная ошибка вызовов функций состоит в том, что они думают, чтоthis
Ситуация во внутренней функции такая же, как и во внешней функции.
Правильно говоря, контекст внутренней функции зависит только от типа ее вызова, а не от контекста внешней функции.
кthis
установить желаемое значение, которое можно.call()
или.apply()
Измените контекст внутренней функции или используйте.bind()
Создайте функцию привязки.
В следующем примере вычисляется сумма двух чисел:
const numbers = {
numberA: 5,
numberB: 10,
sum: function() {
console.log(this === numbers); // => true
function calculate() {
console.log(this === numbers); // => false
return this.numberA + this.numberB;
}
return calculate();
}
};
numbers.sum(); // => NaN
sum()
это вызов метода объекта, поэтомуsum
Контекст в томnumbers
объект.calculate
функция находится вsum
определено в , вы можете захотетьcalculate()
серединаthis
также значитnumber
объект.
calculate()
является вызовом функции (а не вызовом метода), он будетthis
как глобальный объектwindow
(в нестрогом режиме). даже если внешняя функцияsum
поставить контекст какnumber
объект, которыйcalculate
Внутри эффекта нет.
sum()
Результат вызова -NaN
, не ожидаемый результат5 + 10 = 15
, все потому что он не правильно называетсяcalculate
.
Для решения этой проблемы,calculate
Контекст в функции должен быть таким же, какsum
как в так, чтобы вы могли получить доступnumberA
а такжеnumberB
Атрибуты.
Одно из решений - позвонитьcalculator.call(this)
Вручнуюcalculate
Измените контекст на нужный контекст.
const numbers = {
numberA: 5,
numberB: 10,
sum: function() {
console.log(this === numbers); // => true
function calculate() {
console.log(this === numbers); // => true
return this.numberA + this.numberB;
}
// 使用 .call() 方法修改上下文
return calculate.call(this);
}
};
numbers.sum(); // => 15
call(this)
Выполнить как обычноcalculate
функция, ноcall
изменит контекст на значение, указанное в качестве первого параметра.
Сейчасthis.numberA
+ this.numberB
эквивалентноnumbers.numberA + numbers.numberB
. Функция возвращает ожидаемый результат5 + 10 = 15
.
Другой - использовать функции стрелок
const numbers = {
numberA: 5,
numberB: 10,
sum: function() {
console.log(this === numbers); // => true
const calculate = () => {
console.log(this === numbers); // => true
return this.numberA + this.numberB;
}
return calculate();
}
};
numbers.sum(); // => 15
3. Вызов метода
Методы — это функции, хранящиеся в свойствах объекта. Например
const myObject = {
// helloFunction 是一个方法
helloFunction: function() {
return 'Hello World!';
}
};
const message = myObject.helloFunction();
helloFunction
даmyObject
Метод , чтобы вызвать этот метод, вы можете назвать его так:myObject.helloFunction
.
Когда выражение выполняется в форме доступа к свойству, выполняется вызов метода, который эквивалентен функции, за которой следует (, набор аргументов, разделенных запятыми, и ).
Используя предыдущий пример,myObject.helloFunction()
является объектомmyObject
тот, что наhelloFunction
вызов метода.[1, 2].join(',')
или/\s/.test('beautiful world')
Также считается вызовом метода.
Важно различать вызовы функций и вызовы методов, поскольку они относятся к разным типам. Основное отличие состоит в том, что для вызова метода требуется форма доступа к свойству для вызова функции (obj.myFunc()
илиobj['myFunc']()
), при этом вызов функции не требует (myFunc()
).
['Hello', 'World'].join(', '); // 方法调用
({ ten: function() { return 10; } }).ten(); // 方法调用
const obj = {};
obj.myFunction = function() {
return new Date().toString();
};
obj.myFunction(); // 方法调用
const otherFunction = obj.myFunction;
otherFunction(); // 函数调用
parseFloat('16.60'); // 函数调用
isNaN(0); // 函数调用
Понимание разницы между вызовом функции и вызовом метода помогает правильно определить контекст.
3.1 Как это выглядит при вызове метода?
При вызове метода
this
Является ли объект с этим методом
При вызове метода объектаthis
становится самим объектом.
Создайте объект, у которого есть метод для увеличения числа
const calc = {
num: 0,
increment: function() {
console.log(this === calc); // => true
this.num += 1;
return this.num;
}
};
// method invocation. this is calc
calc.increment(); // => 1
calc.increment(); // => 2
передачаcalc.increment()
Сделатьincrement
Контекст функции становитсяcalc
объект. так что используйтеthis.num
увеличиватьnum
свойство действительно.
Давайте посмотрим на другой пример. Объекты JS наследуют метод от прототипа, когда унаследованный метод вызывается для объекта, контекст вызова по-прежнему является самим объектом
const myDog = Object.create({
sayName: function() {
console.log(this === myDog); // => true
return this.name;
}
});
myDog.name = 'Milo';
// 方法调用 this 指向 myDog
myDog.sayName(); // => 'Milo'
Object.create()
создать новый объектmyDog
, и установите его прототип в соответствии с первым аргументом.myDog
наследование объектовsayName
метод.
воплощать в жизньmyDog. sayname()
час,myDog
является вызывающим контекстом.
в ЕС6class
В грамматике контекст вызова метода также является самим экземпляром.
class Planet {
constructor(name) {
this.name = name;
}
getName() {
console.log(this === earth); // => true
return this.name;
}
}
var earth = new Planet('Earth');
// method invocation. the context is earth
earth.getName(); // => 'Earth'
3.2 Ошибка: отделение метода от его объекта
Методы могут быть извлечены из объекта в отдельную переменнуюconst alone = myObj.myMethod
. Когда метод вызывается один, то же самое, что и исходный объектalone()
разделение, можно подумать, что текущийthis
это объект, который определяет методmyObject
.
Если метод вызывается без объекта, то происходит вызов функции, в этот моментthis
указывает на глобальный объектwindow
Строгий режимundefined
.
Следующий пример определяетAnimal
Конструктор и создайте его экземпляр:myCat
. потомsetTimout()
печать через 1 секундуmyCat
информация об объекте
function Animal(type, legs) {
this.type = type;
this.legs = legs;
this.logInfo = function() {
console.log(this === myCat); // => false
console.log('The ' + this.type + ' has ' + this.legs + ' legs');
}
}
const myCat = new Animal('Cat', 4);
// The undefined has undefined legs
setTimeout(myCat.logInfo, 1000);
ты можешь подуматьsetTimout
передачаmyCat.loginfo()
когда он должен печатать оmyCat
информация об объекте.
К сожалению, методы отсоединяются от объектов при передаче в качестве параметров.setTimout(myCat.logInfo)
Следующие случаи эквивалентны:
setTimout(myCat.logInfo);
// 等价于
const extractedLogInfo = myCat.logInfo;
setTimout(extractedLogInfo);
будут разделеныlogInfo
При вызове как функцииthis
является глобальнымwindow
, поэтому информация об объекте печатается неправильно.
можно использовать функцию.bind()
Метод привязан к объекту, и его можно решитьthis
указал на проблему.
function Animal(type, legs) {
this.type = type;
this.legs = legs;
this.logInfo = function() {
console.log(this === myCat); // => true
console.log('The ' + this.type + ' has ' + this.legs + ' legs');
};
}
const myCat = new Animal('Cat', 4);
// logs "The Cat has 4 legs"
setTimeout(myCat.logInfo.bind(myCat), 1000);
myCat.logInfo.bind(myCat)
Возвращает новую функцию, которая выполняется так же, какlogInfo
точно так же, но на этот разthis
направлениеmyCat
, даже в вызовах функций.
Другое решение - поставитьlogInfo()
Метод определяется как стрелочная функция:
function Animal(type, legs) {
this.type = type;
this.legs = legs;
this.logInfo = () => {
console.log(this === myCat); // => true
console.log('The ' + this.type + ' has ' + this.legs + ' legs');
};
}
const myCat = new Animal('Cat', 4);
// logs "The Cat has 4 legs"
setTimeout(myCat.logInfo, 1000);
4. Вызов конструктора
когдаnew
Ключевое слово вызывается сразу после объекта функции (, набора параметров, разделенных запятыми, и ), который выполняет вызов конструктора, напримерnew RegExp('\\d')
.
объявилCountry
функцию и вызовите ее как конструктор:
function Country(name, traveled) {
this.name = name ? name : 'United Kingdom';
this.traveled = Boolean(traveled);
}
Country.prototype.travel = function() {
this.traveled = true;
};
// 构造函数调用
const france = new Country('France', false);
// 构造函数调用
const unitedKingdom = new Country;
france.travel(); // Travel to France
new Country('France', false)
даCountry
Вызов конструктора функции. Результатом его выполнения являетсяname
собственность'France'
новый объект. Если этот конструктор вызывается без аргументов, круглые скобки можно опустить:new Country
.
Начиная с ES6, JS позволяет использоватьclass
ключевые слова для определения конструкторов
class City {
constructor(name, traveled) {
this.name = name;
this.traveled = false;
}
travel() {
this.traveled = true;
}
}
// Constructor invocation
const paris = new City('Paris', false);
paris.travel();
new City('Paris')
это вызов конструктора. Этот объект инициализируется специальным методом в этом классеconstructor
обрабатывать. в,this
Указывает на вновь созданный объект.
Конструктор создает новый пустой объект, который наследует свойства прототипа конструктора. Роль конструктора заключается в инициализации объекта. Как вы, вероятно, уже знаете, в этом типе вызова контекст указывает на только что созданный экземпляр.
при доступе к свойствуmyObject.myFunction
есть фронтnew
Когда ключевое слово, JS выполнит вызов конструктора вместо исходного вызова метода.
Напримерnew myObject.myFunction()
: Это эквивалентно извлечению метода с доступом к свойствам.extractedFunction = myObject.myFunction
, а затем используйте его как конструктор для создания нового объекта:new extractedFunction()
.
4.1 это в конструкторах
В вызове конструктора это указывает на вновь созданный объект
Контекст вызова конструктора — это вновь созданный объект. Он инициализирует новые объекты параметрами конструктора, устанавливает начальные значения для свойств, добавляет обработчики событий и многое другое.
Взгляните на контекст в примере ниже
function Foo () {
console.log(this instanceof Foo); // => true
this.property = 'Default Value';
}
// Constructor invocation
const fooInstance = new Foo();
fooInstance.property; // => 'Default Value'
new Foo()
Выполняется вызов конструктора, где контекстfooInstance
. существуетFoo
Внутренний объект инициализации:this.property
присваивается значение по умолчанию.
Такая же ситуация с использованиемclass
Синтаксис (от ES6 итого) также происходит, единственное отличие в том, что инициализация находится вconstructor
в методе:
class Bar {
constructor() {
console.log(this instanceof Bar); // => true
this.property = 'Default Value';
}
}
// Constructor invocation
const barInstance = new Bar();
barInstance.property; // => 'Default Value'
4.2. Подводный камень: забыть использовать новые
Некоторые функции JS создают новые объекты не только при вызове как конструкторы, но и при вызове как функции, напримерRegExp
:
var reg1 = new RegExp('\\w+');
var reg2 = RegExp('\\w+');
reg1 instanceof RegExp; // => true
reg2 instanceof RegExp; // => true
reg1.source === reg2.source; // => true
при исполненииnew RegExp('\\w+')
а такжеRegExp('\\w+')
Когда JS создает эквивалент объекта регулярного выражения.
Существует потенциальная проблема с использованием вызовов функций для создания объектов (за исключением фабричного шаблона), поскольку некоторые конструкторы могут игнорироватьnew
Логика инициализации объекта при использовании ключевого слова.
Следующий пример иллюстрирует проблему:
function Vehicle(type, wheelsCount) {
this.type = type;
this.wheelsCount = wheelsCount;
return this;
}
// 忘记使用 new
const car = Vehicle('Car', 4);
car.type; // => 'Car'
car.wheelsCount // => 4
car === window // => true
Vehicle
является набором объекта контекстаtype
а такжеwheelsCount
функция собственности.
при исполненииVehicle('Car', 4)
, возвращает объектCar
, который имеет правильные свойства:Car.type
дляCar
а такжеCar.wheelsCount
для4
, вы можете подумать, что это удобно для создания и инициализации новых объектов.
Однако при вызове функцииthis
даwindow
объект, поэтомуVehicle('Car',4)
существуетwindow
Задайте свойства объектов. По-видимому, это ошибка, она не создает новый объект.
Когда вы хотите вызвать конструктор, убедитесь, что вы используетеnew
оператор:
function Vehicle(type, wheelsCount) {
if (!(this instanceof Vehicle)) {
throw Error('Error: Incorrect invocation');
}
this.type = type;
this.wheelsCount = wheelsCount;
return this;
}
// Constructor invocation
const car = new Vehicle('Car', 4);
car.type // => 'Car'
car.wheelsCount // => 4
car instanceof Vehicle // => true
// Function invocation. Throws an error.
const brokenCar = Vehicle('Broken Car', 3);
new Vehicle('Car',4)
Работает нормально: новый объект создается и инициализируется, потому что он используется в вызове конструктораnew
ключевые слова.
Добавлена проверка конструктораthis instanceof Vehicle
чтобы убедиться, что контекст выполнения имеет правильный тип объекта. еслиthis
нетVehicle
, то будет выдано сообщение об ошибке. Таким образом, если вы выполнитеVehicle('Broken Car', 3)
(нетnew
), получаем исключение:Error: Incorrect invocation
.
5. Неявный вызов
использоватьmyFun.call()
илиmyFun.apply()
Когда метод вызывает функцию, выполняется неявный вызов.
Функции в JS являются объектами первого класса, что означает, что функции являются объектами, а объекты имеют типFunction
. Из списка методов функционального объекта,.call()
а также.apply()
Используется для вызова функций с настраиваемым контекстом.
-
метод
.call(thisArg[, arg1[, arg2[, ...]]])
первый параметр, который будет принятthisArg
как контекст во время вызова,arg1, arg2, ...
Они передаются в качестве аргументов вызываемой функции. -
метод
.apply(thisArg, [args])
первый параметр, который будет принятthisArg
в качестве контекста во время вызова и принимает другой массивоподобный объект[arg1, arg2, ...]
Передается в качестве аргумента вызываемой функции.
Ниже приведен пример неявного вызова
function increment(number) {
return ++number;
}
increment.call(undefined, 10); // => 11
increment.apply(undefined, [10]); // => 11
increment.call()
а такжеincrement.apply()
использовать параметры10
Вызывается эта функция автоинкремента.
Разница между ними.call()
Получение набора параметров, например.myFunction.call(thisValue, 'value1', 'value2')
. а также.apply()
Набор принимаемых аргументов должен быть массивоподобным объектом, например.myFunction.apply(thisValue, ['value1', 'value2']
).
5.1 this в неявных вызовах
В неявном вызове .call() или .apply() это первый параметр.
Очевидно, что в неявном вызовеthis
передается в качестве первого параметра.call()
или.apply()
.
var rabbit = { name: 'White Rabbit' };
function concatName(string) {
console.log(this === rabbit); // => true
return string + this.name;
}
concatName.call(rabbit, 'Hello '); // => 'Hello White Rabbit'
concatName.apply(rabbit, ['Bye ']); // => 'Bye White Rabbit'
Неявные вызовы полезны, когда функция должна выполняться в определенном контексте. Например, чтобы разрешить вызовы методов,this
всегдаwindow
или в строгом режимеundefined
вопросы контекста. Неявные вызовы можно использовать для имитации вызова метода объекта.
function Runner(name) {
console.log(this instanceof Rabbit); // => true
this.name = name;
}
function Rabbit(name, countLegs) {
console.log(this instanceof Rabbit); // => true
Runner.call(this, name);
this.countLegs = countLegs;
}
const myRabbit = new Rabbit('White Rabbit', 4);
myRabbit; // { name: 'White Rabbit', countLegs: 4 }
Rabbit
серединаRunner.call(this, name)
Неявно вызывает функцию родительского класса для инициализации объекта.
6. Функции связывания
Связанная функция — это функция, связанная с объектом. обычно используется.bind()
Методы создаются из примитивных функций. Исходные и связанные функции используют один и тот же код и область действия, но выполняются в разных контекстах.
методmyFunc.bind(thisArg[, arg1[, arg2[, ...]]])
принимает первый параметрthisArg
как контекст, в котором выполняется связанная функция, и принимает необязательный набор параметровarg1, arg2, ...
Как параметр модифицированной функции. Он возвращает привязкуthisArg
новая функция.
function multiply(number) {
'use strict';
return this * number;
}
const double = multiply.bind(2);
double(3); // => 6
double(10); // => 20
bind(2)
возвращает новый объект функцииdouble
,double
связать номера2
.multiply
а такжеdouble
имеют тот же код и область действия.
а также.apply()
а также.call()
вместо этого он не вызывает функцию немедленно,.bind()
Метод просто возвращает новую функцию, которая вызывается после, только что已经
предварительно установлен.
6.1 this в связанных функциях
При вызове связанной функции
this
да.bind()
первый параметр .
.bind()
В результате создается новая функция, которая при вызове передает контекст как.bind()
первый параметр . Это мощная техника, которая позволяет нам создать определениеthis
функция стоимости.
Давайте посмотрим, как установить, как связать функциюthis
const numbers = {
array: [3, 5, 10],
getNumbers: function() {
return this.array;
}
};
const boundGetNumbers = numbers.getNumbers.bind(numbers);
boundGetNumbers(); // => [3, 5, 10]
// Extract method from object
const simpleGetNumbers = numbers.getNumbers;
simpleGetNumbers(); // => undefined (严格模式下报错)
numbers.getNumbers.bind(numbers)
обратная привязкаnumbers
объектboundGetNumbers
функция.boundGetNumbers()
когда звонятthis
даnumber
объект и может вернуть правильный объект массива.
функция может бытьnumbers.getNumbers
извлечь в переменнуюsimpleGetNumbers
без привязки. в последующих вызовах функцийsimpleGetNumbers()
изthis
даwindow
(в строгом режиме этоundefined
),нетnumber
объект. В этом случае,simpleGetNumbers()
не возвращает массив правильно.
6.2 Жесткая привязка контекста
.bind()
Создайте постоянную контекстную ссылку и всегда сохраняйте ее. Связанная функция не может пройти.call()
или.apply()
чтобы изменить его контекст, даже повторное связывание не имеет никакого эффекта.
Только вызовы конструктора связанных функций могут изменить уже связанный контекст, но это крайне не рекомендуется (вызовы конструктора должны использовать обычные несвязанные функции).
В следующем примере создается связанная функция, а затем предпринимается попытка изменить ее предопределенный контекст.
function getThis() {
'use strict';
return this;
}
const one = getThis.bind(1);
// 绑定函数调用
one(); // => 1
// 使用带有.apply()和.call()的绑定函数
one.call(2); // => 1
one.apply(2); // => 1
// 再次绑定
one.bind(2)(); // => 1
// 以构造函数的形式调用绑定函数
new one(); // => Object
Толькоnew one()
Изменен контекст связанной функции, другими способами вызоваthis
всегда равен 1.
7. Стрелочные функции
Стрелочные функции используются для объявления функций в более короткой форме и лексической привязки контекста. это можно использовать так
const hello = (name) => {
return 'Hello ' + name;
};
hello('World'); // => 'Hello World'
// Keep only even numbers
[1, 2, 5, 6].filter(item => item % 2 === 0); // => [2, 6]
Синтаксис стрелочной функции прост, не многословен.function
ключевые слова. Когда стрелочная функция имеет только один оператор, ее можно даже опустить.return
ключевые слова.
Стрелочные функции анонимны, что означаетname
свойство представляет собой пустую строку''
. Таким образом, у него нет лексических имен функций (имена функций полезны для рекурсии, разделения обработчиков событий)
Также, в отличие от штатных функций, не обеспечиваетarguments
объект. Однако это работает в ES6 черезrest parameters
Фиксированный:
const sumArguments = (...args) => {
console.log(typeof arguments); // => 'undefined'
return args.reduce((result, item) => result + item);
};
sumArguments.name // => ''
sumArguments(5, 5, 6); // => 16
7.1 this в стрелочных функциях
это определяет объемлющий контекст функции стрелки
Стрелочные функции не создают свой собственный контекст выполнения, они получают его из внешней функции, которая его определяет.this
. Другими словами, стрелочные функции лексически связаныthis
.
Следующий пример иллюстрирует эту контекстно-прозрачную функцию:
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
log() {
console.log(this === myPoint); // => true
setTimeout(()=> {
console.log(this === myPoint); // => true
console.log(this.x + ':' + this.y); // => '95:165'
}, 1000);
}
}
const myPoint = new Point(95, 165);
myPoint.log();
setTimeout
использовать сlog()
метод в том же контексте (myPoint
объект) для вызова функции стрелки. Как видите, стрелочная функция наследует контекст от определяющей ее функции.
Если вы попробуете обычную функцию в этом примере, она создаст свой собственный контекст (window
или в строгом режимеundefined
). Таким образом, чтобы тот же самый код правильно использовал выражения функций, вам нужно вручную связать контекст:setTimeout(function(){…}.bind(this))
. Это многословно, использование стрелочных функций — более чистое и короткое решение.
Если функция стрелки определена в самой верхней области (вне любой функции), контекстом всегда является глобальный объект (окно в браузерах):
onst getContext = () => {
console.log(this === window); // => true
return this;
};
console.log(getContext() === window); // => true
Стрелочные функции раз и навсегда привязаны к лексическому контексту. Даже если контекст изменен,this
Его также нельзя изменить:
const numbers = [1, 2];
(function() {
const get = () => {
console.log(this === numbers); // => true
return this;
};
console.log(this === numbers); // => true
get(); // => [1, 2]
// Use arrow function with .apply() and .call()
get.call([0]); // => [1, 2]
get.apply([0]); // => [1, 2]
// Bind
get.bind([0])(); // => [1, 2]
}).call(numbers);
Вызовите функцию стрелки в любом случаеget
Это всегда сохраняет лексический контекстnumbers
. Неявные вызовы с другими контекстами (черезget.call([0])
илиget.apply([0])
) или перепривязать (через.bind()
) не будет работать.
Стрелочные функции нельзя использовать в качестве конструкторов. вызовите его как конструктор (new get()
) выдаст ошибку:TypeError: get is not a constructor
.
7.2 Подводный камень: определение методов со стрелочными функциями
Вы можете использовать стрелочные функции для объявления методов объекта. Определения стрелочных функций намного короче, чем функциональные выражения:(param) => {...} instead of function(param) {..}
.
Давайте посмотрим на пример, используя стрелочную функцию, определенную в классе Period.format()
метод:
function Period (hours, minutes) {
this.hours = hours;
this.minutes = minutes;
}
Period.prototype.format = () => {
console.log(this === window); // => true
return this.hours + ' hours and ' + this.minutes + ' minutes';
};
const walkPeriod = new Period(2, 30);
walkPeriod.format(); // => 'undefined hours and undefined minutes'
из-заformat
является стрелочной функцией и определяется в глобальном контексте (самая верхняя область видимости), поэтомуthis
направлениеwindow
объект.
хотяformat
вызывается как метод объекта, такого какwalkPeriod.format()
,window
Еще контекст этого звонка. Причина этого в том, что стрелочные функции имеют статический контекст, который не меняется в зависимости от того, как они вызываются.
Метод возвращает'undefined hours和undefined minutes'
, который не тот результат, который мы хотим.
Выражения функций решают эту проблему, потому что регулярные функции действительно могут изменять их контекст на основе фактического вызова:
function Period (hours, minutes) {
this.hours = hours;
this.minutes = minutes;
}
Period.prototype.format = function() {
console.log(this === walkPeriod); // => true
return this.hours + ' hours and ' + this.minutes + ' minutes';
};
const walkPeriod = new Period(2, 30);
walkPeriod.format(); // => '2 hours and 30 minutes'
walkPeriod.format()
это вызов метода для объекта, контекст которогоwalkPeriod
объект.this.hours
равный2
,this.minutes
равный30
, поэтому этот метод возвращает правильный результат:'2 hours and 30 minutes'
.
оригинал:Поездка на рис avlutin.com/gentle-ex довольно…
Ошибки, которые могут существовать после развертывания кода, не могут быть известны в режиме реального времени.Чтобы решить эти ошибки впоследствии, много времени тратится на отладку журнала.Кстати, я рекомендую всем полезный инструмент мониторинга ошибок.Fundebug.
Суммировать
для пары вызовов функцийthis
Самое большое влияние, отныне не спрашивайте себя:
откуда это?
но видеть
Как называется функция?
Для стрелочных функций подумайте о
Где определена эта стрелочная функция, что это?
это обработкаthis
Когда правильные идеи, они могут избавить вас от головной боли.
общаться с
Статья постоянно обновляется каждую неделю. Вы можете выполнить поиск «Big Move to the World» в WeChat, чтобы прочитать и обновить ее как можно скорее (на одну или две статьи раньше, чем в блоге). Эта статья находится на GitHub.GitHub.com/QQ449245884…Он был включен, и многие мои документы были разобраны. Добро пожаловать в Звезду и совершенство. Вы можете обратиться в тестовый центр для ознакомления во время собеседования. Кроме того, обратите внимание на паблик-аккаунт и ответьте в фоновом режиме.Благосостояние, вы можете увидеть преимущества, вы знаете.