Практический проект | Прочитав ECMAScript 6 г-на Руана Ифэна, я так много подытожил✍

внешний интерфейс
Практический проект | Прочитав ECMAScript 6 г-на Руана Ифэна, я так много подытожил✍

globalThisобъект верхнего уровня

Язык JavaScript имеет объект верхнего уровня, который обеспечивает глобальную среду (т. е. глобальную область действия), в которой выполняется весь код. Однако объекты верхнего уровня неодинаковы для разных реализаций. В среде браузера относится кwindowобъект, вNodeОтноситсяglobalобъект.ES5Среди них свойства объекта верхнего уровня эквивалентны глобальным переменным.

var a = 2;
window.a // 2

ES6Чтобы изменить это, оговорено, с одной стороны, что для сохранения совместимостиvarкоманда иfunctionОбъявленная командой глобальная переменная по-прежнему является свойством объекта верхнего уровня, с другой стороны оговаривается, чтоletЗаказ,constЗаказ,classГлобальная переменная, объявленная командой, не является свойством объекта верхнего уровня. То есть изES6Первоначально глобальные переменные будут постепенно отделяться от свойств объекта верхнего уровня.

var a = 2;
window.a // 2

let b = 3
window.b //undefined
  • Внутри браузера объект верхнего уровняwindow,ноNodeа такжеWeb Workerнетwindow.
  • браузер иWeb Workerв,selfтакже указывает на объект верхнего уровня, ноNodeнетself.
  • NodeВнутри находится объект верхнего уровняglobal, но никакая другая среда не поддерживает его.

ES2020На уровне языковых стандартов введениеglobalThisкак объект верхнего уровня. То есть при любых обстоятельствахglobalThisВсе существуют, и из них можно получить объект верхнего уровня, указывающий на глобальную средуthis.

Destructuring

ES6 позволяет извлекать значения из массивов и объектов и присваивать значения переменным по определенному шаблону, который называется деструктурированием

Array Destructuring

let [a, , b, ...c] = [1, 2, 3, 4, 5]
a   // 1
b   // 3
c   // [4,5]

//error
let [a] = 1  //不具备 Iterator 接口

let [a, b = 2, c = 3] = [1, , undefined]
a //1,
b //2,
c //3

let [x = 1, y = x] = [];     // x=1; y=1
let [x = y, y = 1] = [];     // ReferenceError: y is not defined

//交换位置
let x = 1, y = 2;
[y, x] = [x, y]
x // 2
y // 1

Object Destructuring

Objectдеконструкция иArrayЕсть важное отличие. Элементы массива расположены по порядку, а значение переменной определяется ее позицией; иObjectизpropПорядок отсутствует, переменная должна быть такой же, какpropодно и то же имя, чтобы получить правильноеvalue.

let { foo, baz } = { foo: 'aaa', bar: 'bbb' };
foo // 'aaa'
baz // undefined

//解构对象方法
let { log, sin, cos } = Math;
const { log } = console;

Как объяснялось выше, присваивание объекта деструктурированию является сокращением для следующей формы

let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined

let obj = {
  p: [
    'Hello',
    { y: 'World' }
  ]
};
let { p: [x, { y }] } = obj;
p // p is not defined  // p是模式,不参与赋值
x // "Hello"
y // "World"
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]

Tip: присваивание деструктуризации объекта может извлекать унаследованные свойства.

const obj1 = {};
const obj2 = { foo: 'bar' };
Object.setPrototypeOf(obj1, obj2);

const { foo } = obj1;
foo // "bar"

При установке значения по умолчанию условие для того, чтобы значение по умолчанию вступило в силу, состоит в том, что значение свойства объекта строго равноundefined.

var { message: msg = 'Something went wrong', say } = { say() { console.log(`say`) } };
msg // Something went wrong
say // function say(){}

Symbol

Представляет уникальное значение. этоJavaScriptСедьмой тип данных языка.Первые шесть:undefined,null, логическое значение(Boolean), нить(String), стоимость(Number), объект(Object)

let sy = Symbol('a')
let sy1 = Symbol('a')
sy === sy1  // false
sy.toString() === sy1.toString() // true
// ES2019 提供 description
sy.description === sy1.description // true

let s1 = Symbol.for('foo');
let s2 = Symbol.for('foo');
s1 === s2 // true

Symbol.for()а такжеSymbol()Эти два способа письма порождают новыеSymbol. Разница между ними в том, что первые будут регистрироваться в глобальной среде поиска, вторые — нет.Symbol.for()не возвращает новый каждый раз, когда он вызываетсяSymbolзначение типа, но сначала проверит данныйkeyНезависимо от того, существует ли оно уже, если нет, будет создано новое значение. Например, если вы позвонитеSymbol.for("foo")30 раз, каждый раз возвращает одно и то же Symbolценность, но вызовSymbol("foo")30 раз, вернет 30 разныхSymbol стоимость.

Symbol.iterator

Свойство объекта Symbol.iterator, указывающее на метод итератора объекта по умолчанию. Запомни это

const myIterable = {};
myIterable[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

[...myIterable]  //  [1, 2, 3]   // ...的底层是for...of

возражать против выполненияfor...ofПри цикле он будет вызыватьсяSymbol.iteratorметод, который возвращает итератор по умолчанию для этого объекта,

class Collection {
  *[Symbol.iterator]() {
    let i = 0;
    while(this[i] !== undefined) {
      yield this[i];
      ++i;
    }
  }
}

let myCollection = new Collection();
myCollection[0] = 1;
myCollection[1] = 2;

for(let value of myCollection) {
  console.log(value);
}
// 1
// 2

Symbol.toStringTag

объектSymbol.toStringTagсвойство, указывающее на метод. вызвать этот объектObject.prototype.toStringметод, если это свойство существует, его возвращаемое значение появится вtoStringСтрока, возвращаемая методом, представляет тип объекта. То есть это свойство можно использовать для настройки[object Object]или[object Array]серединаobjectследующая строка.

({[Symbol.toStringTag]: 'Foo'}.toString())
// "[object Foo]"

class Collection {
  get [Symbol.toStringTag]() {
    return 'xxx';
  }
}
let x = new Collection();
Object.prototype.toString.call(x) // "[object xxx]"

Set && Map

ES6Предоставляет новые структуры данныхSet, Map

SetЗначение члена уникально, нет повторяющихся значений, элементы в наборе строго типизированы, проверка типов.

let set = new Set([1, true, '1', 'true', 1])
// Set(4) {1, true, "1", "true"}

Setручка союза(Union), перекресток(Intersect)сумма и разница(Difference)

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);

// 并集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}

// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}

// (a 相对于 b 的)差集
let difference = new Set([...a].filter(x => !b.has(x)));
// Set {1}

MapПодобно объектам, это также набор пар ключ-значение, но область действия «ключей» не ограничивается строками, и в качестве ключей могут использоваться различные типы значений (включая объекты).

const map = new Map([
  ['name', '张三'],
  ['title', 'Author']
]);

map.size // 2
map.has('name') // true
map.get('name') // "张三"
map.has('title') // true
map.get('title') // "Author"

преобразование между данными

Map To Array

const myMap = new Map()
  .set(true, 7)
  .set({foo: 3}, ['abc']);
[...myMap]
// [ [ true, 7 ], [ { foo: 3 }, [ 'abc' ] ] ]

Array To Map

new Map([
  [true, 7],
  [{foo: 3}, ['abc']]
])
// Map {
//   true => 7,
//   Object {foo: 3} => ['abc']
// }

Map To Object

function strMapToObj(strMap) {
  let obj = Object.create(null);
  for (let [k,v] of strMap) {
    obj[k] = v;
  }
  return obj;
}

const myMap = new Map()
  .set('yes', true)
  .set('no', false);
strMapToObj(myMap)
// { yes: true, no: false }

Object To Map

let obj = {"a":1, "b":2};
let map = new Map(Object.entries(obj));

Map To JSON

function strMapToJson(strMap) {
  return JSON.stringify(strMapToObj(strMap));
}

let myMap = new Map().set('yes', true).set('no', false);
strMapToJson(myMap)
// '{"yes":true,"no":false}'

JSON To Map

function jsonToStrMap(jsonStr) {
  return objToStrMap(JSON.parse(jsonStr));
}

jsonToStrMap('{"yes": true, "no": false}')
// Map {'yes' => true, 'no' => false}

WeakSet && WeakMapВсе объекты, на которые ссылаются, являются слабыми ссылками, то есть ссылка не учитывается механизмом сборки мусора. Поэтому, как только другие ссылки на указанный объект очищаются, механизм сборки мусора освобождает память, занятую объектом. То есть, когда он больше не нужен,WeakSet && WeakMapОбъект имени ключа внутри и соответствующее значение ключа автоматически исчезнут без ручного удаления ссылки.

Proxy

Обзор

ProxyМожно понять, что уровень «перехвата» устанавливается перед целевым объектом, и внешний доступ к объекту должен сначала пройти этот уровень перехвата, поэтому предусмотрен механизм фильтрации и перезаписи внешнего доступа.ProxyПервоначальное значение слова - агент, и оно используется здесь для обозначения того, что оно используется для «агента» некоторых операций, что можно перевести как «агент».

а такжеObject.definePropertyиспользуется ли перехват данных:Определите новое свойство непосредственно в объекте или измените существующее свойство объекта и верните этот объект.

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

  • Vue 2.xиспользоватьObject.defineProperty(), и отделить внутренности какObserver, Depи использоватьWatcherсвязаны
  • Vueсуществует3.xПосле использования версииProxyБыть достигнутым

Proxyа такжеObject.definePropertyконтраст

  • Object.defineProperty
    • может только слушать объекты (Object), не может отслеживать изменения в массиве, не может запускатьpush, pop, shift, unshift,splice, sort, reverse.
    • Каждое свойство объекта должно быть пройдено
    • Захват имущества может быть только текущим объектом, если вы хотите захватить глубину, необходимо пройти глубоко вложенный объект
    "use strict"
    let obj = {};
    let value = 1
    Object.defineProperty(obj, 'listenA', {
      writable: true,  //可修改
      enumerable: true,  // 可枚举   for...in...   Object.keys()
      configurable: true,  // 可配置,可删除
      get: () => value,
      set: val => {
        console.log(`set obj.listenA .. ${val}`);
        value = val
      },
    });
    obj.listenA = 2 //set obj.listenA .. 2
    console.log(obj.listenA)  // 2
    
  • Proxy
    • Вы можете слушать непосредственно объекты, а не свойства
    • Вы можете напрямую отслеживать изменения в массиве
    // 代理整个对象
    let proxyObj = new Proxy({}, {
      get: (target, key, receiver) => {
        console.log(`getting ${key}!`);
        return target[key];
      },
      set: (target, key, value, receiver) => {
        console.log(target, key, value, receiver);
        return target[key] = value;
      },
    });
    proxyObj.val = 1;    // {} val 1 {}
    proxyObj.val;       // getting val!
    
    //代理数组
    let proxyArr = new Proxy([], {
      get: (target, key, receiver) => {
        console.log(`getting ${key}!`);
        return target[key];
      },
      set: (target, key, value, receiver) => {
        console.log(target, key, value, receiver);
        return (target[key] = value);
      },
    });
    proxyArr[0] = 1; //  {} val 1 {}
    console.log(proxyArr[0]); //  getting val!  // 1
    console.log(proxyArr); // [1]
    

Reflect

ReflectПеревод должен означать отражение, сProxyто же, что объектES6новое для манипулирования объектамиAPI. Есть несколько функций

  • БудуObjectМетоды объекта, которые явно являются внутренними для языка (например,Object.defineProperty), вставитьReflectна объекте. На этом этапе некоторые методыObjectа такжеReflectобъект, будущие новые методы будут развернуты только наReflectна объекте. То есть изReflectОбъект может получить метод на языке.
  • Модифицировать некоторыеObjectВозвращаемый результат метода делает его более разумным. Например,Object.defineProperty(obj, name, desc)Ошибка выдается, когда свойство не может быть определено, иReflect.defineProperty(obj, name, desc)вернусьfalse.
 // 老写法
try {
  Object.defineProperty(target, property, attributes);
  // success
} catch (e) {
  // failure
}

// 新写法
if (Reflect.defineProperty(target, property, attributes)) {  // 成功返回true
  // success
} else {
  // failure
}
  • ПозволятьObjectОперации становятся функциональным поведением. немногоObjectОперация — это команда, напримерname in objа такжеdelete obj[name],а такжеReflect.has(obj, name)а такжеReflect.deleteProperty(obj, name)Сделайте их функциональным поведением.
// 老写法
'assign' in Object // true

// 新写法
Reflect.has(Object, 'assign') // true
  • Reflectметоды объекта иProxyМетоды объекта соответствуют один к одному, пока онProxyметоды объекта, вы можетеReflectНайдите соответствующий метод на объекте. Это позволяет прокси-объекту легко позвонить соответствующемуReflectметод, который завершает поведение по умолчанию, в качестве основы для изменения поведения. То есть независимо отProxyКак изменить поведение по умолчанию, вы всегда можетеReflectчтобы получить поведение по умолчанию.
Proxy(target, {
  set: function(target, name, value, receiver) {
    var success = Reflect.set(target, name, value, receiver);
    if (success) {
      console.log('property ' + name + ' on ' + target + ' set to ' + value);
    }
    return success;
  }
});

async function

ES2017введен стандартasyncфункция, делающая асинхронные операции более удобными, потому чтоasync函数то, что возвращаетсяPromiseпредмет, который можно использовать какawaitПараметры команды.

async function timeout(ms) {
  await new Promise((resolve) => {
    setTimeout(resolve, ms);
  });
}

async function asyncPrint(value, ms) {
  await timeout(ms);
  console.log(value);
}

asyncPrint('hello world', 50);

вернутьPromiseобъект

async function f() {
  return 'hello world';
}

f().then(v => console.log(v))
// "hello world"

asyncВнутри функции возникает ошибка, которая приведет к возвратуPromiseобъект становитсяrejectусловие. Выброшенный объект ошибки будетcatchполучена функция обратного вызова метода

async function f() {
  throw new Error('出错了');
}

f().then(
  v => console.log('resolve', v),
  e => console.log('reject', e)
)
//reject Error: 出错了

Promiseизменение состояния объекта

asyncвозвращается функциейPromiseобъекта, должен дождаться, пока все внутренниеawaitпосле командыPromiseПосле выполнения объекта произойдет изменение состояния, если только он не встретитreturnзаявление или выдать ошибку. То есть толькоasyncАсинхронная операция внутри функции будет выполняться после выполненияthenФункция обратного вызова, указанная методом.

async function getTitle(url) {
  let response = await fetch(url);
  let html = await response.text();
  return html.match(/<title>([\s\S]+)<\/title>/i)[1];
}
getTitle('http://localhost:8080/').then(console.log(123))

awaitЗаказ

При нормальных обстоятельствах,awaitЗа командой следуетPromiseобъект, возвращает результат этого объекта. если неPromiseобъект, он напрямую возвращает соответствующее значение.

async function f() {
  // 等同于
  // return 123;
  return await 123;
}

f().then(v => console.log(v))
// 123

любойawaitСледующие утвержденияPromiseобъект становитсяrejectсостояние, то весьasyncфункция прервет выполнение.

async function f() {
  await Promise.reject('出错了');
  await Promise.resolve('hello world'); // 不会执行
}

Если вы хотите не прерывать последующие асинхронные операции, даже если предыдущая не удалась. В это время первыйawaitпомещатьtry...catchструктуру, чтобы независимо от успеха асинхронной операции второйawaitбудет казнен.

async function f() {
  try {
    await Promise.reject('出错了');
  } catch(e) {
  }
  return await Promise.resolve('hello world');
}

f()
.then(v => console.log(v))
// hello world

asyncКак работает функция

БудуФункция генератораи автоисполнитель, завернутый в функцию

async function fn(args) {
  // ...
}

// 等同于

function fn(args) {
  return spawn(function* () {
    // ...
  });
}

function spawn(genF) {
  return new Promise(function(resolve, reject) {
    const gen = genF();
    function step(nextF) {
      let next;
      try {
        next = nextF();
      } catch(e) {
        return reject(e);
      }
      if(next.done) {
        return resolve(next.value);
      }
      Promise.resolve(next.value).then(function(v) {
        step(function() { return gen.next(v); });
      }, function(e) {
        step(function() { return gen.throw(e); });
      });
    }
    step(function() { return gen.next(undefined); });
  });
}

строгий режим

Модули ES6 автоматически используют строгий режим, независимо от того, добавляете ли вы"use strict";

Строгий режим в основном имеет следующие ограничения.

  • Переменные должны быть объявлены перед использованием
  • Параметры функции не могут иметь атрибуты с одинаковыми именами, иначе будет сообщено об ошибке
  • нельзя использоватьwithутверждение
  • Нельзя присваивать значения свойствам только для чтения, иначе будет сообщено об ошибке
  • Вы не можете использовать префикс 0 для представления восьмеричного числа, иначе будет сообщено об ошибке
  • Невозможно удалить неудаляемые атрибуты, иначе будет сообщено об ошибке
  • Переменная не может быть удаленаdelete prop, будет выдано сообщение об ошибке, удалить можно только атрибутdelete global[prop]
  • evalне вводит переменные во внешнюю область видимости
  • evalа такжеargumentsнельзя переназначить
  • argumentsИзменения параметров функции не отражаются автоматически
  • нельзя использоватьarguments.callee
  • нельзя использоватьarguments.caller
  • запретитьthisуказывает на глобальный объект
  • нельзя использоватьfn.callerа такжеfn.argumentsПолучить стек вызовов функций
  • Добавлены зарезервированные слова (например,protected、staticа такжеinterface)

export && import

использоватьexport && importДля выполнения экспорта импорта модуля.

// 写法一
export var m = 1;
// 写法二
var m = 1;
export {m};
// 写法三
var n = 1;
export {n as m};

// 报错
function f() {}
export f;
// 正确
export function f() {};
// 正确
function f() {}
export {f};

import 'lodash';
import 'lodash';  //加载了两次lodash,但是只会执行一次。

export { foo, bar } from 'my_module';  //当前模块不能直接使用foo和bar
// 接口改名
export { foo as myFoo } from 'my_module';
// 整体输出
export * from 'my_module';
//默认接口
export { default } from 'foo';
export { default as es6 } from './someModule';

заключительные замечания

Вышеизложенное - мой опыт после изучения ES6 г-на Жуана Ифэна, надеюсь, вы меня поправите😜

Рекомендация статьи