Вы действительно понимаете функциональные особенности в ES6?

JavaScript
Вы действительно понимаете функциональные особенности в ES6?

Всем привет, увидимся снова.
Праздники быстротечны, в первый рабочий день после нового года очень не хочется вставать утром, поэтому одеваюсь с закрытыми глазами, чтобы не опоздать.
Ладно, ладно, давайте к делу, взбодритесь!

предисловие

Функции являются важной частью всех языков программирования.До появления Es6 синтаксис функций в JavaScript не сильно изменился, оставив много проблем и неясных практик, что привело к необходимости написания большого количества кода для реализации некоторых функций.

значение параметра функции по умолчанию

Особенность функций JavaScript заключается в том, что независимо от того, сколько параметров определяются в параметрах функции, любое количество параметров может быть передано, но в некоторых случаях наши параметры могут быть заполнены только, поэтому мы все еще находимся в телу функции. Написание кучу логики приводит к резервию кода. К счастью, версия ES6 имеет функциональные значения по умолчанию.

Сравним коды Es5 и Es6

Es5 обрабатывает параметры по умолчанию

function person(name, age) {
    name = typeof(name) != "undefined" ? name : `蛙人${+ new Date()}`
    age = typeof(age) != "undefined" ? age : 24
    
}
person()

В приведенном выше примере Es5 обрабатывает значения параметров по умолчанию таким образом.Если у нас будет слишком много параметров, будет очень избыточно писать код таким образом, поэтому Es6 имеет значения параметров функции по умолчанию.

Es6 обрабатывает параметры по умолчанию

function person(name = "蛙人", age = 24) {
    console.log(name, age)
}
person()  // 蛙人 24
person("张三", 30) // 张三 30
person(null, null) // null null

В приведенном выше примере параметр по умолчанию обрабатывается в Es6. Вы можете видеть, что код очень упрощен. В приведенном выше коде вы можете видеть, что параметр передается в значении null, что также является допустимым значением для параметра по умолчанию. В этом случае он будет использоваться только в том случае, если параметр функции не определен.

выражение параметра функции

Что касается значений параметров по умолчанию, наиболее интересной особенностью может быть то, что в параметры передаются непримитивные значения, а параметры по умолчанию также могут быть определены как函数or 变量.

function defaultName() {
    return "蛙人"
}
function person(name = defaultName()) {
    console.log(name)
}
person("张三") // 张三
person() // 蛙人

Следует отметить, что выражение параметра по умолчанию выполняется не сразу после создания функции, а при создании функции.personВыполняется при вызове без передачи аргументов.

В приведенном выше примере, если никакие параметры не переданы, будет вызвано значение по умолчаниюdefaultNameфункция.

Давайте посмотрим на параметры по умолчанию, передаваемые в переменных.

let defaultName = "蛙人"
function person(name = defaultName) {
     console.log(name)
}
person("张三") // 张三
person() // 蛙人
function person(name, nickName = name) {
     console.log(name, nickName)
}
person("张三") // 张三 张三
person("蛙人", "掘金蛙人") // 蛙人 掘金蛙人

В приведенном выше примере мы можем понять внутреннюю часть первого блока кода, но заменим предыдущую функцию переменной. Глядя на код во втором блоке кода, мы ставимnickNameЗначение параметра по умолчанию установлено на первый параметрnameПараметр, это при ссылке на значение параметра по умолчанию, разрешено ссылаться только на значение предыдущего параметра, что эквивалентно параметру функции, является определенной переменной, наша последняя переменная может получить доступ к предыдущей переменной, но это эта функция ограничена только текущей областью действия Параметром является текущая область. Давайте посмотрим на другой пример.

function person(name = nickName, nickName) {
     console.log(name, nickName)
}
person("张三") // 张三 undefined

В приведенном выше примере значением по умолчанию первого параметра является второй параметр. В это время операция выдаст ошибку, потому что доступ ко второй переменной до ее определения вызовет временную мертвую зону. Если вы не понимаете временную мертвая зона Вы можете перейти к моей прошлой статье.«Разница между var, let и const, которую вы можете понять с первого взгляда»

Влияние значений параметров функции по умолчанию на аргументы

Объект Arguments ведет себя по-разному при использовании аргументов функции по умолчанию

Использование аргументов в нестрогом режиме Es5

В нестрогом режиме Es5 изменение именованных параметров функции будет отражено вargumentsна объекте,argumentsПолучает фактические параметры текущей функции,argumentsВ нестрогом режиме это отношение отображения с формальными параметрами, то есть формальные параметры изменяютсяargumentsСледите за изменением.

function test(a, b) {
    console.log(a == arguments[0]) // true
    console.log(b == arguments[1]) // true
    a = "a"
    b = "b"
    console.log(arguments) // ["a", "b"]
}
test(1, 2)

В приведенном выше примере в нестрогом режиме изменения именованных параметров будут обновляться синхронно сargumentsв объекте. когдаaИзменения параметров будут отображены наarguments[0]на объекте.

Использование аргументов в строгом режиме Es5

Давайте посмотрим на строгий режимarguments

 function test(a, b) {
    'use strict';

    console.log(arguments)  // [1, 2]
    b = 10
    console.log(arguments) // [1, 2]
}
test(1, 2)

Приведенный выше пример находится в строгом режиме, видно, что когда мы меняем параметрыb, распечатать сноваargumentsобъект, который также является значением инициализации. в строгом режимеJavaScriptотменен вargumentsВозражайте против этого запутанного поведения, независимо от того, как изменяется параметр,argumentsОбъект больше не меняется вместе с ним.

Влияние использования значений параметров по умолчанию на аргументы в Es6

В Es6, если функция использует значения параметров по умолчанию, тоargumentsПоведение объекта будет таким же, какJavaScriptСогласован в строгом режиме.

 function test(a, b = 2) {
    a = 12
    b = 10
    console.log(arguments) // [1]
}
test(1)

В приведенном выше примереargumentsраспечатать объект[1]Потому чтоargumentsОбъект получает фактический параметр, мы видим, что параметру фактического параметра передается значение, поэтомуargumentsОбъект имеет только одно значение. Посмотрите на второй пункт,aа такжеbпараметры изменили значения, ноargumentsОбъект все еще не изменился, о чем я сказал выше,如果一个函数使用了默认参数值,那么arguments对象的行为都将与JavaScript中的严格模式下保持一致.

Обработка безымянных параметров

Количество параметров функции в js произвольное, когда передается меньшее количество, функция параметров по умолчанию может эффективно упростить код объявления функции. Es6 также обеспечивает лучшее решение, когда передается больше объемов.

Получить безымянные параметры в Es5

function test(a, b, c) {
    console.log(arguments) // [1, 2, 3]
}
test(1, 2, 3)

В приведенном выше примереargumentsОбъекты тоже могут достигать всех параметров, но если мы хотим получить все параметры после второго параметра, то придется зацикливаться.

Получить безымянные параметры в Es6

function test(...parmas) {
    console.log(params) // [1, 2, 3, 4]
}
test(1, 2, 3, 4)
function test(a, b, ...params) {
    console.log(params)
}
test(1, 2, 3, 4)

В приведенном выше примере первый блок кода реализует получение всех параметров в Es6, но это не соответствует нашим потребностям. Затем смотрим код во втором блоке кода, и мы получаем все параметры после второго параметра.

Es6 получает недостатки неназванных параметров

​ Прежде всего, каждая функция может объявить только один переменный параметр, и его можно поместить только в конец функции, иначе будет сообщено об ошибке.

function test(...params, a, b) {
	
}
test()

В приведенном выше примере будет выброшена ошибка После объявления неопределенного количества параметров вы не сможете продолжить объявление параметров позже.
Еще один момент, неопределенные параметры не могут быть определены в литерале объектаsetterв, потому чтоsetterФункция получает только одну функцию, и это будет массив после того, как он будет записан как неопределенный параметр, что вызовет исключения программы.

let obj = {
  set name(...params) {

  }
}

атрибут имени функции

существуетJavaScriptВсе функции вnameсвойство, которое содержит строку имени функции. Функция без имени по-прежнему имеетnameсвойства,nameЗначение свойства — пустая строка.

function person() {}
let test = function() {}

console.log(person.name) // person
console.log(test.name) // test

В приведенном выше примереpersonфункцияnameЗначением атрибута является «человек», что соответствует имени функции на момент объявления. выражение анонимной функцииtestфункциональныйnameИмя, соответствующее переменной, присвоенной анонимной функции.

Особый случай атрибута name

Я изначально думал, что каждая функцияnameВсе имена соответствуют текущему имени функции, но позже было обнаружено, что это не так. Рассмотрим частный случай функции

var person = {
    get getName() {
        return "蛙人"
    }
}
console.log(Object.getOwnPropertyDescriptor(person, 'getName').get.name)  // get getName

function test() {}
console.log(test.bind().name) // bound test

В приведенном выше примереperson.getNameявляется функцией стоимостиgetter, поэтому имя его функцииget getName,еслиsetterфункция, то имя будет иметь префиксset. пройти черезbindСозданы функции, имена которых имеют префикс «bound».

стрелочная функция

Функция стрелки в Es6 — одна из самых интересных функций, функция стрелки — это своего рода стрелка использования.=>Новый синтаксис для определения функций, но он отличается от традиционногоJavaScriptФункции немного отличаются, подробности см. в следующих пунктах.

  • нетthis,super,arguments
  • не могу пройтиnewвызов ключевого слова
  • нет прототипаprototype
  • не может быть измененthisнаправление
  • Повторяющиеся именованные параметры не поддерживаются

Стрелочные функции, как и традиционные функции, имеют неизменный атрибут имени.

Синтаксис стрелочной функции

let person = () => "蛙人"

// 相当于下代码

function person() {
	return "蛙人"
}

В приведенном выше примере, когда вычисляется выражение справа от стрелочной функции, оно возвращается немедленно.

Параметры стрелочной функции

let getName = val => val

// 相当于下代码

function getName(val) {
    return val
}

Когда стрелочная функция имеет только один параметр, вы можете опустить круглые скобки и написать имя параметра напрямую. Если вы хотите передать два или более параметра, вам нужно поставить круглые скобки. см. пример ниже

let sum = (a, b) => a + b

// 相当于下代码

function sun(a, b) {
    return a + b
}

Если вы хотите вернуть литерал объекта, вы можете написать

let getObj = () => ({name: "蛙人", age: 24}) // {name: "蛙人", age: 24}

// 相当于下代码

function getObj() {
    return {
    	name: "蛙人",
        age: 24
    }
}

Стрелочные функции не имеют этого

стрелочная функцияthisзначение, зависящее от значения нестрелочной функции вне функцииthisЗначение, если верхний слой все еще стрелочная функция, то продолжить поиск вверх, если не найдено, тоthisто естьwindowобъект

let person = {
    test: () => {
        console.log(this)
    },
    fn() {
        return () => {
            console.log(this)
        }
    }
}
person.test()  // window
person.fn()()  // person对象

В приведенном выше примере хорошо видно, что стрелка неthis, то егоthisОн найдет только функции, которые не являются стрелочными функциями во внешнем слое.

Стрелочные функции неargumentsобъект

Также не работает стрелкаargumentsобъект, но если во внешнем слое есть слой нестрелочных функций, он найдет функцию внешнего слоя.argumentsобъект следующим образом

let test1 = () => console.log(arguments)  // 执行该函数会抛出错误


function test2(a, b, c) {
    return () => {
        console.log(arguments) // [1, 2, 3]
    }
}
test2(1, 2, 3)()

В приведенном выше примере вы можете ясно видеть, что текущая стрелочная функция не работает.argumentsобъект, но перейдите к его внешнему слою, чтобы найти функции, которые не являются стрелочными функциями.注意:箭头函数找arguments对象只会找外层非箭头函数的函数,如果外层是一个非箭头函数的函数如果它也没有arguments对象也会中断返回,就不会在往外层去找了. см. пример ниже

function test(a) {
    return function() {
        return () => {
            console.log(arguments) // []
        }
    }
}
test(1)()()

Как вы можете видеть в приведенном выше примере, стрелочная функция внутри ищет нестрелочную функциональную функцию во внешнем слое, а затем независимо от того, имеет ли внешний слой эту функцию или нетargumentsобъекты возвращаются. Только это не стрелочная функция, и если внешний слой является стрелочной функцией, она продолжит искать внешний слой.

Функции стрелок не могут быть использованыnewобъявление ключевого слова

let test = () => {}
new test() // 抛出错误,找不到constructor对象

Стрелочные функции не имеют прототипаprototype

Помните, стрелочные функции не имеют прототипов, и интервьюер может спросить:JavaScriptВсе функции в наличииprototypeатрибут?

let test = () => {}
test.prototype // undefined

Функции стрелок не могут быть измененыthisнаправление

let person = {}
let test = () => console.log(this)

test.bind(person)()
test.call(person)
test.apply(person)

В приведенном выше примере изменитеthisНи один из указанных методов не вызовет ошибку, но ни один из них недействителен и не может быть изменен.thisнаправление.

Функция стрелки не может повторить параметры именования

let sum = (a, a) => {} // 抛出错误,参数不能重复

Если вы считаете, что это хорошо написано, то ставьте палец вверх!

Вы также можете добавить мой WeChat для общения