Веб-интервью — JavaScript

внешний интерфейс

1. О замыканиях

Что такое закрытие?
Закрытие — это функция, которая имеет доступ к переменным в области действия других функций.
В JS переменная делится на глобальные переменные и локальные переменные, роль локальных переменных принадлежит функциональному полю, а домен функции будет уничтожен после выполнения функции, а память будет восстановлена, но поскольку замыкание построенные внутри функции Subfremers, благодаря их доступу к вышестоящей области видимости, даже если вышестоящая функция будет выполнена, область видимости не будет уничтожена, в это время дочерняя функция - это замыкание, имеющее доступ -level Scope.Разрешения, даже если значения в области действия в функциональном домене были выполнены, не будут уничтожены.

Что решают замыкания?
По сути, замыкание — это мост между внутренней частью функции и внешней частью функции. Поскольку замыкание может кэшировать верхнюю область видимости, переменные внутри функции могут быть доступны вне функции.

Сценарии применения замыканий
Обратный вызов для успешного запроса ajax
Метод обратного вызова, привязанный к событию
Задержка обратного вызова setTimeout
Внутри функции возвращается другая анонимная функция

Плюсы и минусы закрытия
Преимущества: сделать код более стандартизированным и лаконичным.
Недостатки: используется слишком много замыканий, большое потребление памяти, возникают утечки памяти.

2. Прототипы и цепочки прототипов

я не могу прочитать эту картинку这张图看不懂可以不看

(1) Все ссылочные типы имеют свойство __proto__ (неявный прототип), а значением свойства является обычный объект
(2) В дополнение к атрибуту __proto__ все функции также имеют атрибут прототипа (явный прототип), а значением атрибута является обычный объект
(3) Все ссылочные типы имеют атрибут конструктора (constructor), который (является указателем) указывает на его конструктор
(4.) Атрибут __proto__ всех ссылочных типов указывает на прототип его конструктора

Когда объект вызывает свойство/метод, который не существует сам по себе, он обращается к своему _proto_, чтобы найти его, то есть к прототипу своего конструктора; если он не найден, он обращается к _proto_ прототипа конструктора чтобы указать «Поиск» в прототипе функции верхнего уровня и, наконец, указать на ноль. Такая взаимосвязь, просматривающаяся слой за слоем, сформирует цепную структуру, называемую цепочкой прототипов.

Глубокое понимание прототипа JS и цепочки прототипов

Понимайте конструктор, прототип, __proto__ и цепочку прототипов по-своему (график)

Пример для понимания прототипа и цепочки прототипов JS

3. Наследование ES5 и наследование ES6

ES5:
Комбинированное наследование, сначала создать экземпляр объекта подкласса, а затем добавить к этому метод родительского класса через метод вызова, и реализовать его через механизм прототипа и конструктора

Пример:

// 定义一个父类
function Parent() {
    this.name = '爸爸'
    this.age = 50
    this.sex = '男'
}
// 在父类的原型上添加一个方法
Parent.prototype.play = function () {
    console.log('去打麻将')
}

// 定义一个子类
function Child(name) {
    this.name = name
    // 第一步:继承父类的属性
    Parent.call(this)
}
// 第二步:实现子类继承父类的方法(儿子从爸爸那里学会了打麻将)
Child.prototype = new Parent()
// 第三步:找回丢失的构造函数
Child.prototype.constructor = Child

ЭС6:
Сначала создайте объект экземпляра this родительского класса (поэтому вы должны сначала вызвать метод super() родительского класса, а затем изменить его с помощью конструктора подкласса), определить класс с помощью ключевого слова class и реализовать наследование между классами с помощью ключевое слово extends.Подклассы должны вызывать метод super в методе конструктора. Потому что подкласс не имеет своего объекта this, а наследует объект this родительского класса, а затем обрабатывает его, и если суперметод не вызывается, то подкласс не может получить объект this.

Пример:

// 定义一个父类
class Parent {
    constructor(name, sex) {
        this.name = name
        this.sex = sex
    }
    play() {
        console.log(this.name + '打麻将超级垃圾')
    }
    speak() {
        console.log('性别是:' + this.sex)
    }
}
// 父类的实例化
let father = new Parent('老高','男')
father.play() // 打麻将超级垃圾
father.speak() // 性别是男

// 创建一个子类去继承父类
class Child extends Parent{
    constructor(name, sex) {
        // 调用父类的 constructor
        super(name, sex)
    }
}
// 子类的实例化
let son = new Child('小高', '女')
son.play()
son.speak()

4. Нативные шаги запроса AJAX

Пять шагов использования:
(1) Создайте объект XMLHTTPRequest.
(2) Используйте открытый метод, чтобы установить информацию о взаимодействии с сервером.
(3) Установите данные для отправки и начните взаимодействовать с сервером.
(4) Регистрационное мероприятие
(5). Обновите интерфейс

Получить запрос:

// 第一步:创建异步对象
let xhr = new XMLHttpRequest()
// 第二步:设置请求的url参数,参数1是请求的类型,参数2是请求的url,可以携带参数
xhr.open('get', '/baidu.com?username=1')
// 第三步:设置发送的数据,开始和服务端交互
xhr.send()
// 第四步:注册事件onreadystatechange,当状态改变时会调用
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        // 第五步:如果到达这一步,说明数据返回,请求的页面是存在的
        console.log(xhr.responseText)
    }
}

Почтовый запрос:

// 第一步:创建异步对象
let xhr = new XMLHttpRequest()
// post请求一定要添加请求头,不然会报错
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
// 第二步:设置请求的url参数,参数1是请求的类型,参数2是请求的url,可以携带参数
xhr.open('post', '/baidu.com')
// 第三步:设置发送的数据,开始和服务端交互
xhr.send('username=1&password=123')
// 第四步:注册事件onreadystatechange,当状态改变时会调用
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && xhr.status === 200) {
        // 第五步:如果到达这一步,说明数据返回,请求的页面是存在的
        console.log(xhr.responseText)
    }
}

5. О делегировании мероприятия

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

Роль делегации мероприятия
(1) Повышение производительности: каждая функция будет занимать место в памяти, просто добавьте обработчик времени для проксирования всех событий, занимая меньше места в памяти;
(2) Динамический мониторинг: использование делегирования событий может автоматически связывать динамически добавляемые элементы, то есть новые узлы не нужно активно добавлять, и они могут иметь те же события, что и другие элементы.

Метод реализации
Давайте сначала посмотрим, как это реализовать, когда вам нужно связать несколько одинаковых событий без делегирования событий:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul>
    <li class="item">按钮</li>
    <li class="item">按钮</li>
    <li class="item">按钮</li>
    <li class="item">按钮</li>
</ul>
</body>
<script>
    window.onload = function () {
        let lis = document.getElementsByClassName('item')
        for (let i = 0; i < lis.length; i++) {
            lis[i].onclick = function () {
                console.log('用力的点我')
            }
        }
    }
</script>
</html>

Если вы не используете делегирование событий, вам нужно обойти каждый элемент li и привязать событие клика к каждому элементу li. Этот метод очень интенсивно использует память. Если элементов li 100 или 1000, это окажет большое влияние на производительность.

Так как же реализовано использование делегирования событий?

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<ul id="wrap">
    <li class="item">按钮</li>
    <li class="item">按钮</li>
    <li class="item">按钮</li>
    <li class="item">按钮</li>
</ul>
</body>
<script>
    window.onload = function () {
        let ul = document.getElementById('wrap')
        ul.onclick = function (ev) {
            // 获取到事件对象
            let e = ev || window.event
            // 如果点击的元素的calssName为item
            if (e.target.className === 'item') {
                console.log('用力的点我')
            }
        }
    }
</script>
</html>

Таким образом, посредством делегирования события необходимо привязать только событие щелчка к родительскому элементу ul элемента li, а эффект щелчка li может быть достигнут с помощью механизма всплытия событий. И динамически добавляйте элементы li через js, вы также можете привязывать события кликов.

6.null не является объектом, но почему typeof null === object

Принцип таков: различные объекты будут представлены как двоичные на нижнем уровне.В js, если все первые три бита двоичного кода равны 0, он будет оцениваться как тип объекта.Двоичный код null равен всем 0, а первые три, естественно, равны 0. Итак, typeof null === objcet.

7. О глубоком копировании и мелком копировании

Мелкая копия:
Скопируйте только указатель на объект, а не сам объект, старый и новый объекты по-прежнему используют одну и ту же память.

выполнить:

Способ 1: прямое использование = присвоение

let obj1 = {a: 1}
let obj2 = obj1

Способ 2: Object.assign
Уведомление:
(1) Не копирует унаследованные свойства объекта
(2) Он не будет копировать неперечислимые свойства объекта
(3) Он может копировать атрибуты типа Symbol

let obj1 = {a: 1}
let obj2 = {}
Object.assign(obj2, obj1)

Способ 3. Цикл for in проходит только по первому слою.

function shallowObj(obj) {
    if (typeof obj === 'object' && obj !== null) {
        let result = Array.isArray(obj) ? [] : {}
        for (let key in obj) {
            if (Object.hasOwnProperty(key)) {
                result[key] = obj[key]
            }
        }
        return result
    } else return obj
}

let obj1 = {
    a: 1,
    b: {
        c: 2
    }
}
let obj2 = shallowObj(obj1)
obj1.b.c = 3
console.log(obj2.b.c) // 3

Глубокая копия:
Способ 1. Используйте JSON.stringify для преобразования объекта в строку, а затем используйте JSON.parse для преобразования строки в новый объект.

let obj1 = {
    a: 1,
    b: 2,
}
let obj2 = JSON.parse(JSON.stringify(obj1))

Способ 2. Используйте рекурсию для копирования всех иерархических атрибутов.

function deepClone(obj) {
    // 如果传入的值不是一个对象,就不执行
    if (Object.prototype.toString.call(obj) !== '[object Object]') return
    // 根据传入值的类型初始化返回结果
    let result = obj instanceof Array ? [] : {}
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            // 如果obj是个对象,就递归调用deepClone去遍历obj的每一层属性,如果不是对象就直接返回值
            result[key] = Object.prototype.toString.call(obj[key]) === '[object Object]' ? deepClone(obj[key]) : obj[key]
        }
    }
    return result
}
// 改进判断对象的方法
console.log(typeof null === 'object') // true
console.log(Object.prototype.toString.call(null) === '[object Object]') // false

Способ 3: библиотека lodash реализует глубокую копию

let obj1 = {
    a: 1,
    b: 2,
}
let obj2 = _.cloneDeep(obj1)

Способ 4: глубокое копирование с помощью метода расширения jQuery

let array = [1,2,3,4]
let newArray = $.extend(true,[],array) // true为深拷贝,false为浅拷贝

Способ 5: Реализация глубокой копии массива со срезом

let arr1 = ["1","2","3"]
let arr2 = arr1.slice(0)
arr2[1] = "9"
console.log(arr2) // ['1', '9', '3']
console.log(arr1) // ['1', '2', '3']

Способ 6: Глубокое копирование с использованием оператора распространения

let obj1 = {brand: "BMW", price: "380000", length: "5米"}
let obj2 = { ...car, price: "500000" }

Разница и реализация мелкой и глубокой копии js

8. Расскажите о механизме сборки мусора js

JS имеет автоматический механизм сбора мусора. Когда значение утратило ссылку в памяти, механизм сборки мусора находит его в соответствии со специальным алгоритмом, и восстанавливает его, выпускает память.

Метод маркировки и развертки (обычно используется)
(1) Этап маркировки: сборщик мусора будет проходить от корневого объекта. Каждому объекту, к которому можно получить доступ из корневого объекта, будет добавлен идентификатор, поэтому объект помечен как достижимый объект;
(2) Фаза очистки: сборщик мусора будет линейно перемещаться по памяти кучи от начала до конца. будет достигнута метка.Идентификация объекта очищается для следующей операции сборки мусора;

Преимущество: простота реализации
Недостаток: может вызвать сильную фрагментацию памяти.

очистка подсчета ссылок
(1). Смысл подсчета ссылок заключается в отслеживании и записи количества ссылок на каждое значение. Когда переменная объявляется и ей присваивается ссылочный тип, количество ссылок на это значение равно 1. И наоборот, если переменная, содержащая ссылку на это значение, принимает другое значение, количество ссылок на это значение уменьшается на 1.
(2) Когда количество ссылок становится равным 0, это означает, что доступ к этому значению отсутствует, и занимаемое им пространство памяти может быть переработано. Таким образом, при следующем запуске сборщика мусора он освободит память, занятую значениями, счетчик ссылок которых равен 0.

преимущество:
(1) Мусор можно перерабатывать немедленно

недостаток:
(1) Обработка увеличения и уменьшения значения счетчика тяжелая.
(2) Реализация громоздкая и сложная.
(3) Циклические ссылки не могут быть переработаны

9. Как остановить пузырьки событий и событий по умолчанию

В стандартных объектах DOM метод stopPropagation() объекта события может использоваться для предотвращения всплытия события, но объект события в IE8 и более ранних версиях может предотвратить всплывание, установив для свойства cancelBubble объекта события значение true.

Событие по умолчанию предотвращается методом preventDefault() объекта события, а IE предотвращает событие по умолчанию, устанавливая для свойства returnValue объекта события значение false.

10. Функция подавления дребезга и функция дросселирования

Функция дебаунса (debounce):
При вызове функции в течение n секунд действие будет выполнено, при повторном вызове функции в течение этих n секунд предыдущий вызов будет отменен, а время выполнения будет пересчитано (в случае частого срабатывания код будет выполняться только один раз, если достаточно времени простоя)

function debounce(delay, cb) {
    let timer
    return function () {
        if (timer) clearTimeout(timer)
        timer = setTimeout(function () {
            cb()
        }, delay)
    }
}

Тема JavaScript: изучите защиту от сотрясений с помощью подчеркивания

Функция дроссельной заслонки:
Основная идея дросселирования функции заключается в том, что функция предварительно устанавливает цикл выполнения.Когда время, когда вызывается действие, больше или равно циклу выполнения, действие выполняется, а затем вводится следующий новый цикл (метод js запускается только один раз в определенный период времени. Например, человеческое моргание, то есть моргание один раз в определенный период времени)

function throttle(cb, delay) {
    let startTime = Date.now()
    return function () {
        let currTime = Date.now()
        if (currTime - startTime > delay) {
            cb()
            startTime = currTime
        }
    }
}

Тема JavaScript: научитесь сокращать количество потоков с помощью подчеркивания

11. Расскажите о механизме событийного цикла js

После того, как программа начинает выполняться, основная программа начинает выполнять синхронную задачу, и когда она сталкивается с асинхронной задачей, она ставится в очередь задач.После того, как все синхронные задачи выполнены, js-движок проверяет, нет ли асинхронных задачи, которые могут выполняться в очереди задач. Преобразуйте асинхронную задачу в синхронную и начните ее выполнение. После выполнения синхронной задачи продолжайте просматривать очередь задач. Этот процесс всегда зациклен, поэтому этот процесс является так называемым циклом событий, где очередь задач также называется очередью событий. Через очередь задач однопоточный js реализует выполнение асинхронных задач, давая людям ощущение многопоточности.

12. Отличие стрелочных функций от обычных функций

Обычная функция:
(1).this всегда представляет своего прямого вызывающего абонента
(2) По умолчанию прямой вызывающий абонент не найден, и это указывает на окно
(3) В строгом режиме this в функции без прямого вызывающего объекта не определено.
(4) Используйте call, apply, bind для привязки, это относится к связанному объекту

Функция стрелки:
(1) При использовании => для определения функции указатель this является объектом, в котором она была определена, а не объектом, в котором она использовалась, а bind(), call() и apply() не могут изменить указатель.
(2) Его нельзя использовать как конструктор, то есть нельзя использовать новую команду, иначе будет выброшена ошибка
(3) Нельзя использовать объект arguments, но можно использовать параметр ...rest
(4) Нельзя использовать команду yield
(5) Нет атрибута прототипа

13. Отличие и реализация call(), apply(), bind()

call(), apply(), bind() используются для изменения направления этого

вызов(): Function.call(obj, param1,param2,param3)
Получены param1, param2, param3 три параметра

применять(): Function.apply(obj, [param1,param2,param3])
Получены param1, param2, param3 три параметра

Разница между call и apply в том, что один параметр не использует [], а другой использует []

связывать(): const newFn = Funtion.bind(obj, param1,param2)
Возвращаемое значение — это функция, которая требует () для вызова
newFn(param3,param4)
Получены param1, param2, param3, param4 четыре параметра

Реализация вызова:

Function.prototype.call = function (context, ...args) {
  var context = context || window;
  context.fn = this;
  var result = eval('context.fn(...args)');
  delete context.fn
  return result;
}

применить реализацию:

Function.prototype.apply = function (context, args) {
  let context = context || window;
  context.fn = this;
  let result = eval('context.fn(...args)');
  delete context.fn
  return result;
}

Реализация привязки:

Function.prototype.bind = function (context, ...args) {
    if (typeof this !== "function") {
      throw new Error("this must be a function");
    }
    var self = this;
    var fbound = function () {
        self.apply(this instanceof self ? this : context, args.concat(Array.prototype.slice.call(arguments)));
    }
    if(this.prototype) {
      fbound.prototype = Object.create(this.prototype);
    }
    return fbound;
}

14. Реализуйте функцию сна

js не имеет метода sleep(), как java, но поскольку js является однопоточным, можно использовать псевдобесконечный цикл для блокировки основного потока для достижения эффекта отложенного выполнения.

function sleep(delay) {
    // 获取一个初始时间
    let startTime = new Date().getTime()
    // 如果时间差小于延迟时间,就一直循环
    while (new Date().getTime() - startTime < delay) {
        continue
    }
}

15. Разница между процессом и потоком

Обработать:Это наименьшая единица распределения ресурсов ЦП (наименьшая единица, которая может владеть ресурсами и работать независимо), а также основная единица для одновременного выполнения программ для выделения ресурсов и управления ими во время выполнения.Это динамическая концепция.

Поток (поток):Это наименьшая единица планирования ЦП (единица выполнения программы, основанная на процессе), планируемая сущность внутри процесса и базовая единица, которая меньше процесса и работает независимо.

Процесс имеет один или несколько потоков, и потоки работают вместе для выполнения задач, назначенных процессом.Например:
● Если процесс является фабрикой, фабрика имеет собственные ресурсы.
● Заводы независимы друг от друга
● Потоки — это рабочие на фабрике, и несколько рабочих совместно выполняют задачи.
● На фабрике есть один или несколько рабочих
● Общее пространство между работниками

Уточните и усовершенствуйте концепцию:
● Заводские ресурсы -> выделенная системой память (независимая часть памяти)
● взаимная независимость между фабриками -> взаимная независимость между процессами
● Несколько рабочих взаимодействуют для выполнения задач -> несколько потоков взаимодействуют для выполнения задач в процессе.
● На фабрике есть один или несколько рабочих -> процесс состоит из одного или нескольких потоков.
● Общее пространство между рабочими процессами -> общее пространство памяти программы (включая сегменты кода, наборы данных, кучи и т. д.) между потоками одного процесса.

Говоря о браузере многопроцесс и нить JS

16. Новые возможности ES6, ES7, ES8

Особенности ES6

(1).Класс (класс)
Для разработчиков, знакомых с Java, C, C++ и другими языками, класс не является незнакомым. В ES6 появились классы, чтобы сделать объектно-ориентированное программирование на JS более простым и понятным.

(2).Модуль (Модуль)
ES5 не поддерживает нативную модульность, в ES6 модули были добавлены как важная часть. Функция модуля в основном состоит из экспорта и импорта. Каждый модуль имеет свою собственную область видимости.Отношения взаимного вызова между модулями заключаются в указании интерфейса, предоставляемого модулем посредством экспорта, и в обращении к интерфейсу, предоставляемому другими модулями, посредством импорта. Он также создает пространства имен для модулей, чтобы предотвратить конфликты имен для функций.

экспорт (экспорт)
ES6 работает в модуле, использующем экспорт для экспорта нескольких переменных или функций.

// 导出变量
export let name = 'gg'

// 导出常量
export const name = 'gg'

// 导出多个变量
let a = 2
let b = 4
export {a, b}

// 导出函数
export function myModule(someArg) {
    return someArg
}  

импорт (импорт)
После того, как выходные данные модуля определены, на них можно ссылаться посредством импорта в другом модуле.

import {myModule} from 'myModule'
import {a,b} from 'test'

(3) Функция стрелки
Это одна из самых захватывающих функций в ES6. => Это не просто сокращение для функции ключевого слова, но и другие преимущества. Функция стрелки разделяет то же самое с окружающим ее кодом, что может очень хорошо решить проблему этого указания.

(4) Значение параметра функции по умолчанию
ES6 поддерживает установку значения по умолчанию для функции при ее определении, когда параметром функции является логическое значение false, некоторых проблем можно избежать.

// 使用默认值
function foo(height = 50, color = 'red') {
    //
}

// 不使用默认值
function foo(height, color) {
    let height = height || 50
    let color = color || 'red'
}

(5) Строка шаблона

// 不使用模板字符串
let name = 'Your name is ' + first + ' ' + last + '.'

// 使用模板字符串
let name = `Your name is ${first} ${last}.`

(6) Разрушающее присвоение
Деструктурирующее присваивание может легко поменять местами значения двух переменных:

let a = 1
let b = 3

[a, b] = [b, a];
console.log(a) // 3
console.log(b) // 1

Получить значение в объекте:

const student = {
    name:'Ming',
    age:'18',
    city:'Shanghai'
}

const {name,age,city} = student
console.log(name) // "Ming"
console.log(age) // "18"
console.log(city) // "Shanghai"

(7) Оператор спреда и оператор покоя
Когда три точки (...) находятся справа от знака равенства или на фактическом параметре, это оператор спреда.

myFunction(...arr)

let arr1 = [1, 2, 3, 4]
let arr2 = [...arr1, 4, 5, 6]
console.log(arr2) // [1, 2, 3, 4, 4, 5, 6]

Когда три точки (...) находятся слева от знака равенства или на формальном параметре, это остаточный оператор

function myFunction(...arr) {

}

let [a,...temp]=[1, 2, 4]
console.log(a) // 1
console.log(temp) // [2, 4]

(8) Аббревиатура свойства объекта
ES6 позволяет нам устанавливать свойства объекта без указания имени свойства.

Без ES6:

const name='Ming',age='18',city='Shanghai';

const student = {
    name:name,
    age:age,
    city:city
};
console.log(student)//{name: "Ming", age: "18", city: "Shanghai"}

Использование ES6:

const name='Ming',age='18',city='Shanghai'

const student = {
    name,
    age,
    city
};
console.log(student)//{name: "Ming", age: "18", city: "Shanghai"}

(9).Promise
Промисы — это решение для асинхронного программирования, более элегантное, чем традиционный обратный вызов решения. Впервые он был предложен и реализован сообществом, ES6 вписал его в стандарт языка, унифицированное использование и изначально предоставил объекты Promise.

Не использую ES6

setTimeout(function()
{
    console.log('Hello') // 1秒后输出"Hello"
    setTimeout(function()
    {
        console.log('Hi') // 2秒后输出"Hi"
    }, 1000)
}, 1000)

Используйте ES6

 let waitSecond = new Promise(function(resolve, reject)
{
    setTimeout(resolve, 1000)
});

waitSecond
    .then(function()
    {
        console.log("Hello") // 1秒后输出"Hello"
        return waitSecond
    })
    .then(function()
    {
        console.log("Hi") // 2秒后输出"Hi"
    })

(10) Поддержка let и const
В прошлом в JS не было области видимости на уровне блоков. Const и let заполнили этот удобный пробел. И const, и let являются областью действия на уровне блоков.

Разница между let и var:
● Для let не используется продвижение переменной, а также существует временная мертвая зона.Переменная может использоваться только после объявления let.
● переменные let нельзя объявлять повторно
● переменные, объявленные с помощью let, допустимы только в блоках кода let

Особенности ES7

(1).Array.prototype.includes()
Функция include() используется для определения того, содержит ли массив указанное значение, если да, то возвращает true, иначе возвращает false.

let arr = ['react', 'angular', 'vue']
if  (arr.includes('react')) {
    console.log('react存在')
}

(2) Экспоненциальный оператор
Экспоненциальный оператор ** был введен в ES7, ** имеет эквивалент Math.pow(..) .

console.log(Math.pow(2, 10)) // 输出1024

console.log(2**10) // 输出1024

Особенности ES8

(1).async/await
В ES8 добавлена ​​поддержка async/await, которую мы называем асинхронными функциями, что является очень практичной функцией. async/await эквивалентен синтаксическому сахару, который решает проблему ада обратных вызовов.

(2).Object.values()
Object.values() — это новая функция, похожая на Object.keys(), но возвращающая все значения собственных свойств объекта, за исключением унаследованных значений.

const obj = {
    a: 1,
    b: 2,
    c: 3,
}
// 不使用Object.values()
const vals = Object.keys(obj).map(e => obj[e])
console.log(vals) // [ 1, 2, 3 ]

// 使用Object.values()
console.log(Object.values(obj)) // [ 1, 2, 3 ]

(3).Object.entries
Функция Object.entries() возвращает массив пар ключ-значение для собственных перечислимых свойств данного объекта.

const obj = {
    a: 1,
    b: 2,
    c: 3,
}
// 不使用Object.entries()
Object.keys(obj).forEach(key=>{
    console.log('key:'+key+' value:'+obj[key])
})
//key:a value:1
//key:b value:2
//key:c value:3

// 使用Object.entries()
for(let [key,value] of Object.entries(obj1)){
    console.log(`key: ${key} value:${value}`)
}
//key:a value:1
//key:b value:2
//key:c value:3

(4).String padding
В ES8 String добавил две функции экземпляра String.prototype.padStart и String.prototype.padEnd, позволяющие добавлять пустые строки или другие строки в начало или конец исходной строки.

String.padStart(targetLength,[padString])

targetLength: целевая длина, до которой необходимо дополнить текущую строку. Если это значение меньше длины текущей строки, возвращается сама текущая строка.
padString: (необязательно) строка заполнения. Если строка слишком длинная и длина дополненной строки превышает целевую длину, будет сохранена только самая левая часть, а остальные части будут усечены.Значение этого параметра по умолчанию — " ".

console.log('0.0'.padStart(4,'10')) //10.0
console.log('0.0'.padStart(20))//                0.00  
String.padEnd(targetLength,padString])

targetLength: целевая длина, до которой необходимо дополнить текущую строку. Если это значение меньше длины текущей строки, возвращается сама текущая строка.
padString: (необязательно) строка заполнения. Если строка слишком длинная и длина дополненной строки превышает целевую длину, будет сохранена только самая левая часть, а остальные части будут усечены.Значение этого параметра по умолчанию — " ";

console.log('0.0'.padEnd(4,'0')) //0.00    
console.log('0.0'.padEnd(10,'0'))//0.00000000

(5) Допускаются запятые в конце списка параметров функции.

// 不使用ES8
//程序员A
let f = function(a,
                 b
) {
...
}

//程序员B
let f = function(a,
                 b,   //变更行
                 c   //变更行
) {
...
}

//程序员C
let f = function(a,
                 b,
                 c,   //变更行
                 d   //变更行
) {
...
}

// 使用ES8
//程序员A
let f = function(a,
                 b,
) {
...
}

//程序员B
let f = function(a,
                 b,
                 c,   //变更行
) {
...
}

//程序员C
let f = function(a,
                 b,
                 c,
                 d,   //变更行
) {
...
}

(6).Object.getOwnPropertyDescriptors()
Функция Object.getOwnPropertyDescriptors() используется для получения дескрипторов всех собственных свойств объекта, если собственных свойств нет, возвращает пустой объект.

const obj2 = {
	name: 'Jine',
	get age() { return '18' }
};
Object.getOwnPropertyDescriptors(obj2)
// {
//   age: {
//     configurable: true,
//     enumerable: true,
//     get: function age(){}, //the getter function
//     set: undefined
//   },
//   name: {
//     configurable: true,
//     enumerable: true,
//		value:"Jine",
//		writable:true
//   }
// }

Функции ES6, ES7, ES8 в одном пакете (Руководство по изучению ES6, ES7, ES8)

17. Как платформы мониторинга производительности обнаруживают ошибки

глобальный захват
Через глобальный интерфейс код захвата пишется в одном месте.Интерфейсы, которые можно использовать:
(1)
(2).Глобальный мониторинг на уровне фреймворка.Например,interceptor используется в aixos для перехвата.Vue и react имеют свои интерфейсы сбора ошибок.
(3) Благодаря инкапсуляции глобальной функции исключение автоматически перехватывается при вызове функции.
(4) Переопределить метод экземпляра (Patch), обернув слой на основе исходной функции, например, переписав console.error, а также можно перехватывать исключения, когда метод использования остается неизменным.

захват одной точки
Оберните один блок кода в бизнес-код или управляйте им в логическом потоке, чтобы добиться целевого захвата исключений:
(1).попытаться... поймать бросить ошибку
(2) Напишите функцию специально для сбора информации об исключении и вызывайте функцию при возникновении исключения.
(3) Специально написать функцию, чтобы обернуть другие функции, чтобы получить новую функцию. Результат работы новой функции точно такой же, как исходная функция, за исключением того, что исключение может быть поймано, когда происходит исключение, когда происходит исключение.

Исследование внешнего решения для мониторинга исключений

18. Каррирование функций

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

Пример:

function add(a, b) {
    return a + b;
}

// 执行 add 函数,一次传入两个参数即可
add(1, 2) // 3

// 假设有一个 curry 函数可以做到柯里化
var addCurry = curry(add);
addCurry(1)(2) // 3

addCurry(1)(2) = add(1, 2)

выполнить:
(1) Самый простой способ — использовать _.curry библиотеки lodash.

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

// 使用来自 lodash 库的 _.curry
let curriedSum = _.curry(sum)

alert( curriedSum(1, 2) ) // 3
alert( curriedSum(1)(2) ) // 3

(2) Реализация пользовательских функций

function curry(func) {
    return function curried(...args) {
        if (args.length >= func.length) {
            return func.apply(this, args)
        } else {
            return function(...args2) {
                return curried.apply(this, args.concat(args2))
            }
        }
    }
}

let currfn = curry(add)
console.log(currfn(1)(3)) // 4

Каррирование функций в темах JavaScript

19. Что делает новое ключевое слово?

Вызов конструктора с оператором new на самом деле проходит через следующие 4 шага:
(1) Создайте новый объект
(2) Назначьте область конструктора новому объекту (чтобы это указывало на новый объект)
(3) Выполните код в конструкторе (добавьте свойства и методы для этого нового объекта)
(4) Вернуть новый объект

var obj = {}
obj.__proto__ = Base.prototype
Base.call(obj)

20. Что выводят следующие функции?

(1).Каковы выходные значения p1.name и p2.name?

var func1 = function(){
    this.name = 'peter'
    return {
        name: 'jack'
    }
}
var p1 = new func1()
-----------------------
var func2 = function(){
    this.name = 'peter'
    return 'jack'
}
var p2 = new func2()

console.log(p1.name) // jack
console.log(p2.name) // peter

Анализ: у каждой функции есть возвращаемое значение.Если используется оператор return, возвращается значение, за которым следует return.Если return не используется, по умолчанию возвращается значение undefined.
В частности, если функция является конструктором, она по умолчанию возвращает объект this.Если в конструкторе используется оператор return, а за возвратом следует объект, конструктор возвращает этот объект, в противном случае он возвращает этот.

(2) Что выводят a1.info.name, b1.info.name и a2.info.name, b2.info.name соответственно?

var func1 = function(){}
func1.prototype = {
    info : {
        name : 'peter',
        age : 25
    }
}
var a1 = new func1()
var b1 = new func1()

a1.info.name = 'jack'
b1.info.name = 'tom'
------------------------
var fun2 = function(){
    this.info = {
        name : 'peter',
        age : 25
    }
}
var a2 = new fun2()
var b2 = new fun2()

a2.info.name = 'jack'
b2.info.name = 'tom'

console.log(a1.info.name) // tom
console.log(b1.info.name) // tom
console.log(a2.info.name) // jack
console.log(b2.info.name) // tom

Анализ: a1.info.name и b1.info.name сначала будут искать информацию из экземплярных объектов a1 и b1, если не найдут, то будут искать прототип своего конструктора func1, а если найдут , они являются общими.Значением является tom.
A2.Info.name и B2.Info.name, примеры A2 и B2 имеют информацию об этом объекте, тем самым изменяя значение имени в соответствии с информационным объектом в двух экземплярах соответственно.

(3) Что выводят a.name и b.name соответственно?

var func = function(){}
func.prototype = {
    name : 'peter',
    age : 25
}

var a = new func()
var b = new func()

a.name = 'jack'
b.name = 'tom'

console.log(a.name) // jack
console.log(b.name) // tom

Анализ: в этом вопросе нет процесса доступа, он напрямую назначается атрибуту имени объекта экземпляра, поэтому выводом является гнездо и имя соответственно.

21. Пожалуйста, расскажите о принципе instanceOf и вручную реализуйте функцию isInstanceOf (дочерний, родительский)

instanceof в основном используется для определения того, принадлежит ли экземпляр к определенному типу, а также может использоваться для определения того, является ли экземпляр экземпляром своего родительского типа или типа-предка.
принцип:Определите, существует ли объект, на который указывает свойство прототипа конструктора (справа), в цепочке прототипов другого объекта, который необходимо обнаружить (слева).

выполнить:

function isInstanceOf(child, parent) {
   // 这里需要依次判断
   while(true){
     if(child.__proto__  === parent.prototype) return true
     if(child.__proto__ === null) return false
     child = child.__proto__
   }
}

22. Как установить срок действия для localStorage

Сначала перепишите метод set в прототипе, чтобы он мог устанавливать время истечения срока действия.

Storage.prototype.setExpire = (key, value, expire) => {
    let obj = {
        data: value,
        time: Date.now(),
        expire: expire,
    }
    localStorage.setItem(key,JSON.stringify(obj));
}

При использовании get для его получения оцените, истекло ли время.Если оно истекает, удалите localStorage и верните null

Storage.prototype.getExpire= key => {
    const val = localStorage.getItem('key')
    if (!val) return val
    val = json.parse(val)
    if (Date.now() - val.expire > val.time) {
        localStorage.removeItem(key)
        return null
    }
    return val.data
}

23. Как добиться связи между двумя вкладками в браузере в режиме реального времени

Используя localStorage, связь между несколькими вкладками в одном и том же браузере может быть достигнута путем прослушивания событий хранилища;
Уведомление:Возможна только связь между несколькими вкладками в одном браузере, с одним доменным именем, одним и тем же протоколом и одним и тем же портом. В разных браузерах такого эффекта нет.

window.addEventListener("storage",function(event){
            // ....
        },false); 

событие имеет следующие свойства:
домин:Изменившееся доменное имя хранилища;
ключ:Имя ключа для установки или удаления;
новое значение:Если это установленное значение, это будет новое значение, если это удаленное значение, оно будет нулевым;
старое значение:значение ключа до его изменения;

(Продолжение следует, напишу, когда будет время)