Чем больше вы знаете, тем больше вы не знаете
点赞
Посмотри еще раз, аромат остался в руке, и слава
введение
Стрелочные функции — одно из самых интересных и популярных дополнений к ES6.
Эта статья будет разделена на три части:
Первая часть в основном знакомит с основным синтаксисом и использованием стрелочных функций, в том числеthis的指向
Проблема будет освещена.
Вторая часть исследует, как работают стрелочные функции.自执行函数
странное явление в.
В третьей части будет немного面试题目
, чтобы помочь вам понять.
что такое стрелочная функция
Как следует из названия, стрелочные функции — это новый синтаксис для определения функций с использованием (=>), который немного отличается от традиционных функций ES5.
Вот функция, написанная на синтаксисе ES5:
function addTen(num){
return num + 10;
}
addTen(5); // 15
С помощью стрелочных функций ES6 мы можем использовать стрелочные функции для представления:
var addTen = num => num + 10
addTen(5); // 15
Стрелочные функции намного короче! Из-за неявного возврата мы можем опустить фигурные скобки и оператор return.
Важно понимать, как ведут себя стрелочные функции по сравнению с обычными функциями ES5.
Особенности стрелочных функций
более короткий синтаксис
Основной синтаксис следующий:
(参数)=> { statements }
Далее разбираем различные формы написания стрелочных функций:
Когда нет параметров, используйте скобки, представляющие параметры
let f = ()=> 5;
f(); // 5
При наличии только одного параметра круглые скобки можно опустить.
let f = num => num + 5;
f(10); // 15
При наличии нескольких параметров определите несколько параметров в круглых скобках, разделенных запятыми.
let f = (a,b) => a + b;
f(1,2); // 3
Когда в блоке кода стрелочной функции имеется более одного оператора, его необходимо заключить в фигурные скобки и использовать оператор return.
// 没有大括号,默认返回表达式结果
let f1 = (a,b) => a + b
f1(1,2) // 3
// 有大括号,无return语句,没有返回值
let f2 = (a,b) => {a + b}
f2(1,2) // undefined
// 有大括号,有return语句,返回结果
let f3 = (a,b) => {return a + b}
f3(1,2) // 3
Поскольку фигурные скобки интерпретируются как блоки кода, если стрелочная функция возвращает объект напрямую, вы должны заключить объект в круглые скобки, иначе будет сообщено об ошибке.
//报错
let f1 = num => {num:num}
//不报错
let f2 = num => ({num:num})
нельзя вызывать с новым ключевым словом
Нет функционального метода arrow [[Construct]], его нельзя использовать в качестве конструктора.
let F = ()=>{};
// 报错 TypeError: F is not a constructor
let f = new F();
нет прототипа
Поскольку ее нельзя вызвать через ключевое слово new, нет необходимости создавать прототип, поэтому стрелочная функция не имеет свойства прототипа.
let F = ()=>{};
console.log(F.prototype) // undefined
Не может использоваться в качестве функции генератора
В стрелочных функциях нельзя использовать команду yield, поэтому стрелочные функции нельзя использовать в качестве функций-генераторов.
без аргументов, супер, new.target
В стрелочных функциях нет привязки аргументов, super и new.target, и эти значения определяются ближайшей нестрелочной функцией на периферии.
Взяв аргументы в качестве примера, см. следующий код:
let f = ()=>console.log(arguments);
//报错
f(); // arguments is not defined
Поскольку стрелочная функция f определена в глобальной среде, для f нельзя получить значение аргумента окружающей нестрелочной функции, поэтому здесь сообщается об ошибке.
Давайте посмотрим на другой пример:
function fn(){
let f = ()=> console.log(arguments)
f();
}
fn(1,2,3) // [1,2,3]
В приведенном выше коде аргументы внутри стрелочной функции f на самом деле являются аргументами переменной функции fn.
Если вы хотите получить список параметров переменной длины в стрелочной функции, вы можете использовать параметр rest в ES6 для его решения:
let f = (...args)=>console.log(args)
f(1,2,3,4,5) // [1,2,3,4,5]
нет этой привязки
Прежде чем понять проблему этого в стрелочных функциях, давайте вернемся к примеру в ES5:
var obj = {
value:0,
fn:function(){
this.value ++
}
}
obj.fn();
console.log(obj.value); // 1
Этот код прост, ожидается, что obj.value будет увеличиваться на 1 каждый раз, когда вызывается obj.fn().
Теперь давайте немного изменим код:
var obj = {
value:0,
fn:function(){
var f = function(){
this.value ++
}
f();
}
}
obj.fn();
console.log(obj.value); // 0
Мы немного модифицировали код, добавили функцию f в метод obj.fn, а действие добавления 1 к obj.value поместили в функцию f. Но из-за ошибки в дизайне языка javascript this в функции f не совпадает с this в методе obj.fn, поэтому мы не можем получить obj.value.
Чтобы решить такие проблемы, в ES5 мы обычно присваиваем this во внешней функции временной переменной (обычно называемой that, _this, self), и если мы хотим использовать this внешней функции во внутренней функции, получаем через эту временную переменную. Измените код следующим образом:
var obj = {
value:0,
fn:function(){
// 本人喜欢定义为 _this,也有很多人喜欢定义成 that 或 self
var _this = this;
var f = function(){
_this.value ++
}
f();
}
}
obj.fn();
console.log(obj.value); // 1
Из этого примера мы знаем, как решить внутреннюю функцию, чтобы получить this внешней функции в ES5.
Затем давайте посмотрим на разницу в этом указателе стрелочных функций по сравнению с функциями в ES5.
Посмотрите на некоторые определения изНачало работы с стандартами ES6
Объект this в теле стрелочной функции — это объект, в котором он определен, а не объект, в котором он используется.
Итак, как понимать эту фразу?
мы пытаемся использоватьbabelДавайте преобразуем следующий код в код ES5 и посмотрим, что он делает.
function fn(){
let f = ()=>{
console.log(this)
}
}
Давайте посмотрим на преобразованные результаты прямо выше:
Что мы нашли? Это так же, как мы решали внутреннюю функцию, чтобы получить this внешней функции в ES5 раньше, определив временную переменную _this ~
Итак, куда делась функция стрелок?
Ответ заключается в том, что у стрелочных функций вообще нет this!
Итак, можно подытожить, переводя малопонятное определение на просторечие:
- Если во внешнем слое стрелочной функции есть обычная функция, то this стрелочной функции — это this внешней обычной функции.
- Если во внешнем слое стрелочной функции нет обычной функции, то this стрелочной функции является глобальной переменной.
Давайте используем несколько примеров для проверки правил, которые мы заключили:
let obj = {
fn:function(){
console.log('我是普通函数',this === obj)
return ()=>{
console.log('我是箭头函数',this === obj)
}
}
}
console.log(obj.fn()())
// 我是普通函数 true
// 我是箭头函数 true
Из приведенного выше примера мы можем видеть, что эта функция со стрелкой равна этой внешней функции.
Глядя на пример вложения многоуровневой стрелочной функции:
let obj = {
fn:function(){
console.log('我是普通函数',this === obj)
return ()=>{
console.log('第一个箭头函数',this === obj)
return ()=>{
console.log('第二个箭头函数',this === obj)
return ()=>{
console.log('第三个箭头函数',this === obj)
}
}
}
}
}
console.log(obj.fn()()()())
// 我是普通函数 true
// 第一个箭头函数 true
// 第二个箭头函数 true
// 第三个箭头函数 true
В этом примере мы можем знать, что для стрелочных функций this стрелочной функции равно this первой обычной функции во внешнем слое, независимо от того, сколько слоев стрелочных функций вложены друг в друга.
Давайте рассмотрим пример без внешней функции:
let obj = {
fn:()=>{
console.log(this === window);
}
}
console.log(obj.fn())
// true
Этот пример доказывает, что когда нет обычной функции вне стрелочной функции, this стрелочной функции равно глобальному объекту.
Следует отметить, что глобальный объект в среде браузера — это окно, а глобальный объект в среде узла — глобальный, который необходимо различать при проверке.
Стрелочные функции встречают вызов, применяют, связывают
Увидев это, я полагаю, вы уже знаете, что стрелочные функции вообще не имеют собственного this, так что же происходит, когда стрелочные функции сталкиваются с вызовом, применением и связыванием?
Мы знаем, что роль состоит в том, чтобы изменить вызов и применить его к функции, передавая параметры и выполнение функции, Эффект заключается в создании привязки этой новой функции и предустановленных параметров функции.
Однако, поскольку стрелочные функции вообще не имеют своего this, поэтому:
- При использовании метода call или apply в стрелочной функции передаются только параметры и вызывается функция, а указатель this в стрелочной функции не изменяется;
- При использовании метода привязки для стрелочной функции он возвращает только новую функцию с заданным параметром и не привязывает указатель this новой функции.
Давайте проверим:
window.name = 'window_name';
let f1 = function(){return this.name}
let f2 = ()=> this.name
let obj = {name:'obj_name'}
f1.call(obj) // obj_name
f2.call(obj) // window_name
f1.apply(obj) // obj_name
f2.apply(obj) // window_name
f1.bind(obj)() // obj_name
f2.bind(obj)() // window_name
В приведенном выше коде объявлена нормальная функция f1 и стрелочная функция f2.
Указатель this обычной функции является динамически изменяемым, поэтому при использовании вызова, применения и привязки к f1 указатель this внутри f1 изменится.
Указатель this стрелочной функции определяется во время ее определения и никогда не изменится, поэтому при использовании вызова, применения, привязки к f2 параметр входящего контекста игнорируется.
самовыполняющаяся функция
До появления стрелочных функций ES6 самовыполняющиеся функции обычно писались так:
(function(){
console.log(1)
})()
Или напишите так:
(function(){
console.log(1)
}())
Конечно, стрелочные функции также могут использоваться как самовыполняющиеся функции, которые можно записать следующим образом:
(() => {
console.log(1)
})()
Однако большинство людей не ожидают, что следующий способ написания сообщит об ошибке:
(() => {
console.log(1)
}())
Итак, почему он получает ошибку?
Меня долго мучил этот вопрос, пока не прочиталСпецификация ECMAScript® 2015, из которого мы знаем, что стрелочная функция является разновидностью AssignmentExpression, а вызов функции принадлежит CallExpression. Спецификация требует, чтобы при CallExpression левое выражение должно быть MemberExpression или другим CallExpression, а стрелочная функция не принадлежит этим двум выражениям, поэтому При компиляции будет сообщено об ошибке.
Это принцип, подробности см.Спецификация ECMAScript® 2015
Вопрос о стрелочных функциях
В интервью исследование стрелочных функций в основном было сосредоточено на указании ключевого слова arguments и этом указании стрелочной функции.Следующие темы, от более мелкого к более глубокому, приведены для вашей справки.
Тема 1
function foo(n) {
var f = () => arguments[0] + n;
return f();
}
let res = foo(2);
console.log(res); // 问 输出结果
Ответы и анализ
Ответ: 4
У стрелочных функций нет собственных аргументов, поэтому аргументы в вопросе относятся к объекту arguments функции foo. Итак, arguments[0] равно 2, n равно 2, а результат равен 4.
тема вторая
function A() {
this.foo = 1
}
A.prototype.bar = () => console.log(this.foo)
let a = new A()
a.bar() // 问 输出结果
Отвечать
Ответ: неопределенный
Arrow Эта функция не владеет, поэтому эта функция эквивалентна внешней стрелке стрелки не эта функция. Поскольку внешний слой не является обычной функцией стрелки функции, стрелки в этой функции эквивалентны глобальному объекту, поэтому вывод неопределен.
тема три
let res = (function pt() {
return (() => this.x).bind({ x: 'inner' })();
}).call({ x: 'outer' });
console.log(res) // 问 输出结果
Отвечать
Ответ: «внешний».
Эта задача немного сложнее, найдите выход res.
проанализируйте, как показано ниже:
- Найдите возвращаемое значение функции pt после ее вызова с помощью call.
- Это внутри функции pt преобразуется вызовом {x:'outer'}.
- В функции pt функция стрелки генерирует новую функцию через привязку и выполняет ее, а результатом выполнения является возвращаемое значение функции pt.
- Это в стрелочной функции не может быть привязано методом привязки.Это при выполнении стрелочной функции является this из внешней области видимости.
- Когда функция стрелки выполняется, this внешней области видимости равно {x:'outer'}, указанному методом вызова.
- Окончательный результат res является «внешним».
тема четвертая
window.name = 'window_name';
let obj1 = {
name:'obj1_name',
print:()=>console.log(this.name)
}
let obj2 = {name:'obj2_name'}
obj1.print() // 问 输出结果
obj1.print.call(obj2) // 问 输出结果
Отвечать
Ответ: 'имя_окна' 'имя_окна'
Стрелочные функции не имеют собственного this и не могут изменить this в стрелочных функциях через вызов, применение и привязку. Это стрелочной функции зависит от того, есть ли обычная функция во внешнем слое.Если есть обычная функция, это указывает на это в обычной функции.Если во внешнем слое нет обычной функции, это в стрелке функция является глобальным объектом.
В этом вопросе нет обычной функции за пределами функции стрелки, поэтому она указывает на глобальный объект, поэтому результатом является «имя_окна», «имя_окна».
пятая тема
let obj1 = {
name:'obj1_name',
print:function(){
return ()=>console.log(this.name)
}
}
let obj2 = {name:'obj2_name'}
obj1.print()() // 问 输出结果
obj1.print().call(obj2) // 问 输出结果
obj1.print.call(obj2)() // 问 输出结果
Отвечать
Ответ: 'obj1_name' 'obj1_name' 'obj2_name'
this стрелочной функции такое же, как this внешней обычной функции, и не имеет ничего общего с вызовом, применением и связыванием.
В этом вопросе obj1.print возвращает функцию стрелки, this в функции стрелки - это this при вызове obj1.print.
- obj1.print()(): на этот раз в obj1.print будет obj1, поэтому вывод будет obj1_name
- obj1.print().call(obj2): на этот раз в obj1.print будет obj1, поэтому вывод будет obj1_name
- obj1.print.call(obj2)(): на этот раз в obj1.print будет obj2, поэтому вывод будет obj2_name
Ссылаться на
- Глубокое понимание ES6
- Начало работы со стандартами ES6
- Функция стрелки и это ключевое слово
- ЭТОИспользование функции стрелки
- Спецификация ECMAScript® 2015
напиши в конце
- Если в статье есть ошибки, исправьте их в комментариях, если статья вам поможет, добро пожаловать
点赞
а также关注
- Эта статья была впервые опубликована одновременно сgithub, доступны наgithubНайдите больше отличных статей в
Watch
&Star ★
- Для последующих статей см.:строить планы
Добро пожаловать в публичный аккаунт WeChat
【前端小黑屋】
, 1–3 высококачественные высококачественные статьи публикуются каждую неделю, чтобы помочь вам в продвижении вперед.