ECMAScript 6简介(ES-2015)

ES6简介



目录
1.模板文字
2. let和const
3.箭头函数表达式
4.对于...的
5.计算的属性名称
6. Object.assign()
7.休息参数
8.默认参数
9.销毁工作
10.地图
11.设置
12.班级
13.承诺
14.迭代器
15.发电机
16. Sumbol

模板文字(模板字符串)


模板文字是允许在其中使用表达式的字符串文字。 通过它们,您可以使用多行文字和字符串插值。

模板文字包含在反引号(``)中,而不是双或单。 它们可以包含以美元符号和花括号($ {expression})表示的通配符。 替换表达式及其之间的文本将传递给函数。 默认情况下,该函数将所有部分简单地连接成一个字符串。 如果在该行之前有一个表达式(此处为标签),则该模板行称为“标签模板”。 在这种情况下,将使用已处理的模板文字来调用标签表达式(通常是一个函数),您可以在输出之前对其进行修改。 要在模板文字中转义反引号,请指定反斜杠\。

多行文字
换行符是通配符文字的一部分。 使用常规字符串,换行插入将需要以下语法:
console.log('string text line 1\n' + 'string text line 2'); // "string text line 1 // string text line 2" 

与使用模板文字相同:
 console.log(`string text line 1 string text line 2`); // "string text line 1 // string text line 2" 


表达式插值
要将表达式插入正则字符串中,必须使用以下语法:
 var a = 5; var b = 10; console.log('Fifteen is ' + (a + b) + ' and not ' + (2 * a + b) + '.'); // "Fifteen is 15 and not 20." 


现在,借助模板文字,您可以使用“语法糖”,这使这样的替换更易读:
 var a = 5; var b = 10; console.log(`Fifteen is ${a + b} and not ${2 * a + b}.`); // "Fifteen is 15 and not 20." 


嵌套模板
有时,嵌套模式是制作字符串的最短且可能更易读的方法。 只需在反引号模板中放入另一个,然后用$ {}替换它们即可。 例如,如果表达式为true,则可以返回模板文字。
在ES5中:
 var classes = 'header' classes += (isLargeScreen() ? '' : item.isCollapsed ? ' icon-expander' : ' icon-collapser'); 

在不带嵌套的模板文字的ES2015中:
 const classes = `header ${ isLargeScreen() ? '' : (item.isCollapsed ? 'icon-expander' : 'icon-collapser') }`; 

在带有嵌套模板文字的ES2015中:
 const classes = `header ${ isLargeScreen() ? '' : `icon-${item.isCollapsed ? 'expander' : 'collapser'}` }`; 


标签模板
模板文字的扩展形式是带标签的模板。 它们使您可以使用函数来解析模板文字。 该函数的第一个参数包含一个字符串值数组,其余参数包含替换表达式。 结果,该函数应返回汇编的字符串(或完全不同的字符串,如稍后所示)。 函数的名称可以是任何东西。
 var person = 'Mike'; var age = 28; function myTag(strings, personExp, ageExp) { var str0 = strings[0]; // "That " var str1 = strings[1]; // " is a " // ,     // (  )    , //    (""),    . // var str2 = strings[2]; var ageStr; if (ageExp > 99){ ageStr = 'centenarian'; } else { ageStr = 'youngster'; } //     ,     return `${str0}${personExp}${str1}${ageStr}`; } var output = myTag`That ${ person } is a ${ age }`; console.log(output);// That Mike is a youngster 

标记函数不需要返回字符串。

原始行
特殊的raw属性可用于标签模板的第一个参数,它使您能够以输入形式获得字符串,而无需解释。
 function tag(strings) { return strings.raw[0]; } tag`string text line 1 \\n string text line 2`; //  "string text line 1 \\n string text line 2", //  'n'    '\' 

另外,还有一个String.raw()方法,它返回与默认模板函数完全相同的源字符串,并且字符串连接将一起返回。

在ECMAScript 2016中,带标签的模板遵循转义以下字符的规则:
  • 以“ \ u”开头的Unicode字符,例如\ u00A9
  • 以“ \ u {}”开头的Unicode代码点,例如\ u {2F804}
  • 以“ \ x”开头的十六进制字符表示形式,例如,\ xA9
  • 以“ \”开头的字符的八进制表示形式,例如\ 251


let和const


由let和const关键字声明的变量的范围是声明它们的块,并且所有变量都在这些块下。 在这种情况下,let指令的操作类似于var指令的操作。 主要区别在于var指令声明的变量的范围是声明它的整个函数。 除变量外,常量的值不能通过新的赋值来更改,也不能重新定义。 使用const关键字声明变量时,必须使用赋值运算符设置常量的值。

与var变量不同,全局常量不会成为window对象的属性。
需要初始化常量。
您必须在声明的同时指定一个值(这是因为该值无法再更改)。
使用const关键字声明变量会创建一个只读常量(对内存区域的新命名引用)。
这并不意味着所指示的值不变,而是意味着不能重新分配标识符。 例如,如果常量指向对象,则可以修改对象本身。
常数的名称不能与相同作用域的函数或变量的名称重合。

全局范围和块范围之间的差异的一个示例:
 function myFunction() { if (true) let a = 5; console.log(a); //SyntaxError   a     if if (true) var b = 5; console.log(b); //5   b     } 


箭头函数表达式


箭头函数表达式的语法比函数表达式短,并且按词法绑定到this的值(但不绑定自身的this,arguments,super或new.target)。 箭头函数的表达式不允许您指定名称,因此箭头函数是匿名的,除非分配给任何东西。

基本语法
 (param1, param2, …, paramN) => { statements } (param1, param2, …, paramN) => expression // : (param1, param2, …, paramN) => { return expression; } //       : (singleParam) => { statements } singleParam => { statements } //       : () => { statements } () => expression // : () => { return expression; } 


扩展语法
 //     ,     params => ({foo: bar}) // Rest       (param1, param2, ...rest) => { statements } (param1 = defaultValue1, param2, …, paramN = defaultValueN) => { statements } //    var f = ([a, b] = [1, 2], {x: c} = {x: a + b}) => a + b + c; f(); // 6 

有关箭头功能的更多信息,请参见此处

对于...的


语句的for ...在可迭代对象(包括Array,Map,Set,自变量对象等)中执行循环,并在每个迭代步骤为对象的各种属性调用每个值的运算符。

为什么不应该使用for ... in循环进行迭代? 因为取决于引擎,JavaScript可以按随机顺序进行迭代,这可能导致不可预测的结果。 如果一个属性在一次迭代中发生变化,然后又发生变化,则其在循环中的值就是其最后一个值。 在周期到达之前删除的属性将不参与。 可以跳过循环中添加到对象的属性。 通常,如果尚未传递,最好不要在迭代过程中从对象添加,修改或删除属性。 不能保证添加的属性将在循环中访问,在更改后更改,并在删除后删除。 另外,迭代变量是字符串,而不是数字,这意味着如果要使用该变量进行任何计算,则需要将字符串连接起来而不是添加它们。 因此,为了避免逻辑错误,您不应该使用它!

与for ... of循环不同,for ... in循环返回所有枚举的属性,包括那些具有非整数名称和继承属性的属性。

对于...的循环语法
 for (var i of arr) //for ( of ) arr[i] = "something value" 

范例:
 Object.prototype.objCustom = function() {}; Array.prototype.arrCustom = function() {}; let iterable = [3, 5, 7]; iterable.foo = 'hello'; for (let i in iterable) console.log(i); // 0, 1, 2, "foo", "arrCustom", "objCustom" for (let i in iterable) { if (iterable.hasOwnProperty(i)) console.log(i); //  0, 1, 2, "foo" } for (let i of iterable) console.log(i); // 3, 5, 7 

每个对象都将继承objCustom方法,每个数组都将通过在Object.prototype和Array.prototype中创建它们来继承arrCustom方法。 由于原型继承,可迭代对象将继承objCustom和arrCustom方法。

循环仅按创建顺序显示可迭代对象的枚举属性。 由于它们不可枚举,因此不会打印值3、5、7和hello。 显示属性和方法的名称,例如arrCustom和objCustom。

该循环类似于上一个循环,但是使用hasOwnProperty()来检查对象的此属性是其自身的还是继承的。 仅显示自己的属性。 名称0、1、2和foo仅属于对象的实例(不继承)。 不输出arrCustom和objCustom方法,因为它们是继承的。

该循环绕过了Iterable,并显示了在迭代方法中定义的可迭代对象的值,即 不是对象的属性,而是数组3、5、7的值。

计算的属性名称


声明对象及其元素的语法支持计算的属性名称。 这使您可以将表达式添加到方括号[]中,该表达式将被评估为属性的名称。 它类似于模板文字。

计算名称示例:
 var a = () => "world"; var a = { ["a" + (10 - 6)]: { ["some" + "string"]: true, [10 + 20]: 10, [`hello ${a()}`]: a() } } 



Object.assign()


Object.assign()方法用于将其所有枚举属性的值从一个或多个源对象复制到目标对象。 复制后,它返回目标对象。

Object.assign()方法仅将枚举和本机属性从源对象复制到目标对象。 它在源对象上使用内部[[Get]]方法,在目标对象上使用内部[[Set]]方法,因此它也调用getter和setter。 这就是为什么它分配属性而不是简单地复制或定义新属性的原因。 如果所注入的源对象包含吸气剂,则此行为可能使该方法不适合将新属性注入到原型中。 相反,要复制属性定义的原型(包括其枚举的符号),应使用Object.getOwnPropertyDescriptor()和Object.defineProperty()方法。

复制字符串和符号类型的属性。

例如,如果发生错误,则该属性不可写时,将引发TypeError异常,并且目标对象保持不变。

请注意,如果初始值为null或未定义,则Object.assign()方法不会引发异常。

示例:克隆对象
 var obj = { a: 1 }; var copy = Object.assign({}, obj); console.log(copy); // { a: 1 } 

示例:合并对象
 var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object.assign(o1, o2, o3); console.log(obj); // { a: 1, b: 2, c: 3 } console.log(o1); // { a: 1, b: 2, c: 3 },     . 


休息参数


该函数其余参数的语法允许您以数组形式表示一组无限的参数。

如果最后一个命名的函数参数带有前缀...,则它会根据传递给函数的参数的实际数量自动变为一个数组,该数组的元素从0到TheArgs.length。

句法
 function(a, b, ...theArgs) { // ... } 


使用其余参数的语法的示例:
 function name (a, b, ...c) {} name (0, 1, 2, 3,) 

在此示例中,a = 0 b = 1 c [0] = 2 c [1] = 3
如果未传递其余参数,则它将为空数组(与普通参数不同,它将永远不会是未定义的)。

此语法不仅可以在函数参数中使用,还可以在其他地方使用,例如,用于复制和组合数组:

 var a = [ 0, 1, 2 ]; var b = [ 3, 4, 5 ]; var c = [ ...a, ...b ]; // [ 0, 1, 2, 3, 4, 5 ] 


默认参数


如果在不带参数的情况下调用函数,或者显式传递的参数未定义,则默认参数允许您将形式函数参数设置为默认值。

在JavaScript中,在调用函数时未传递值的函数参数采用默认值undefined。 但是,在某些情况下,设置其他默认值可能很有用。 在这种情况下,将使用默认设置。

仅当在函数调用期间未传递此参数的值或显式传递未定义的值时,才将默认值分配给形式参数。

使用默认参数的示例:
 function myFun(a=5) { return a*a; } console.log(myFun()); // 25 


销毁工作


JavaScript表达式中的解构分配语法使您可以使用类似于在对象中声明数组或文字的语法从数组或对象检索数据。

对象或数组声明表达式提供了一种创建同类数据包的简便方法。 创建此类程序包时,您将有机会以任何可能的方式使用它。 您也可以在函数中返回它。

使用破坏性赋值的关键方法之一是用一个运算符读取数据结构,尽管除此之外您还可以找到许多其他用途。

破坏性分配的示例:
 var a, b, rest; [a, b] = [1, 2]; console.log(a); // 1 console.log(b); // 2 [a, b, ...rest] = [1, 2, 3, 4, 5]; console.log(a); // 1 console.log(b); // 2 console.log(rest); // [3, 4, 5] ({a, b} = {a:1, b:2}); console.log(a); // 1 console.log(b); // 2 

您可以在此处看到更多示例。

地图


映射-包含键值对并保留插入顺序的对象。 任何值(对象和基元都可以)用作键。

一个例子:
 var myMap = new Map(); var keyObj = {}, keyFunc = function () {}, keyString = "a string"; //   myMap.set(keyString, "value associated with 'a string'"); myMap.set(keyObj, "value associated with keyObj"); myMap.set(keyFunc, "value associated with keyFunc"); myMap.size; // 3 //   myMap.get(keyString); // "value associated with 'a string'" myMap.get(keyObj); // "value associated with keyObj" myMap.get(keyFunc); // "value associated with keyFunc" myMap.get("a string"); // "value associated with 'a string'" //   keyString === 'a string' myMap.get({}); // undefined,   keyObj !== {} myMap.get(function() {}) // undefined,   keyFunc !== function () {} 

地图与对象的区别:

  • 对象键是线和符号,而任何值都可以是Map键,包括函数,对象和图元。
  • 与对象不同,Map中的键是有序的。 因此,在Map迭代期间,将按插入顺序返回键。
  • 您可以使用size属性轻松获取Map中的元素数量,而Object中的元素数量只能手动确定。
  • Map是一个可迭代的对象,可以直接对其进行迭代,而Object需要手动接收键列表及其迭代。
  • 该对象具有原型,因此具有一组标准的键,如果不小心,这些键可能会与您的键相交。 自ES5发行以来,可以使用map = Object.create(空)进行更改。
  • 在频繁添加或删除键的情况下,Map可以具有更好的性能。

属性和方法:

  • Map.prototype.size-返回Map上的键\值对的数量
  • Map.prototype.set(键,值)-将传递的键\值对添加到Map。 如果指定的键已经存在,则它将被新值覆盖。
  • Map.prototype.get(键)-返回传递的键的值。 如果没有键,则返回undefined
  • Map.prototype.has(key)-如果传递的键存在,则返回true;否则,则返回false
  • Map.prototype.delete(键)-删除指定的键\值对并返回true。 如果密钥不存在,则返回false。
  • Map.prototype.clear()-从Map移除所有键\值对
  • Map.prototype.keys()-为每个元素返回Map上的键的迭代器
  • Map.prototype.values()-返回Map上每个元素的值的迭代器
  • Map.prototype.entries()-为每个元素返回Map上数组[key,value]的迭代器


设置


允许您保存任何类型的原始值,包括基元和其他类型的对象。

集合对象表示可以按插入元素的顺序遍历的值的集合。 Set中元素的值只能出现在一个实例中,以确保其在Set集合中的唯一性。

属性和实例方法集
  • size-返回Set对象中元素的数量。
  • add(value)-将具有给定值的新元素添加到Set对象。 返回一个Set对象。
  • clear()-从Set对象中删除所有元素。
  • delete(value)-删除与该值关联的元素,并返回以前具有(value)的值。 has(value)稍后将返回false。
  • entry()-返回一个新的Iterator对象,该对象包含按插入顺序的Set对象中每个元素的[value,value]数组。 这与Map对象的存储方式相似,因此此处每个条目的键和值都具有相同的值。
  • forEach(callbackFn [,thisArg])-以插入顺序为Set对象中存在的每个值调用一次callbackFn。 如果为thisEach指定了thisArg,它将用作每个回调的this值。
  • has(value)-返回一个布尔值,该布尔值确认Set对象中是否存在具有给定值的元素。
  • values()-返回一个新的Iterator对象,该对象包含按插入顺序设置的Set对象中每个元素的值。

使用设置对象
 var mySet = new Set(); mySet.add(1); // Set { 1 } mySet.add(5); // Set { 1, 5 } mySet.add(5); // Set { 1, 5 } mySet.add("some text"); // Set { 1, 5, 'some text' } var o = {a: 1, b: 2}; mySet.add(o); mySet.add({a: 1, b: 2}); //  o    ,      mySet.has(1); // true mySet.has(3); // false, 3     set mySet.has(5); // true mySet.has(Math.sqrt(25)); // true mySet.has("Some Text".toLowerCase()); // true mySet.has(o); // true mySet.size; // 5 mySet.delete(5); //  5  set mySet.has(5); // false, 5   mySet.size; // 4,     console.log(mySet); // Set {1, 'some text', Object {a: 1, b: 2}, Object {a: 1, b: 2}} 

旁路设置
 //    : 1, "some text", {"a": 1, "b": 2} for (let item of mySet) console.log(item); //    : 1, "some text", {"a": 1, "b": 2} for (let item of mySet.keys()) console.log(item); //    : 1, "some text", {"a": 1, "b": 2} for (let item of mySet.values()) console.log(item); //    : 1, "some text", {"a": 1, "b": 2} //(key  value    ) for (let [key, value] of mySet.entries()) console.log(key); //  Set  Array var myArr = Array.from(mySet); // [1, "some text", {"a": 1, "b": 2}] //       HTML  mySet.add(document.body); mySet.has(document.querySelector("body")); // true //   Array  Set   mySet2 = new Set([1,2,3,4]); mySet2.size; // 4 [...mySet2]; // [1,2,3,4] //      var intersection = new Set([...set1].filter(x => set2.has(x))); //      var difference = new Set([...set1].filter(x => !set2.has(x))); //   set   forEach mySet.forEach(function(value) { console.log(value); }); // 1 // 2 // 3 // 4 



班级


JavaScript中的类在ECMAScript 2015中引入,是JavaScript上原型继承的语法糖。 类语法没有引入新的面向对象模型,但是提供了一种更简单,更直观的方法来创建对象和组织继承。

类实际上是“特殊函数”,因此就像定义函数(函数表达式和函数声明)一样,可以使用以下类定义类:类声明和类表达式。

函数声明和类声明之间的区别在于,函数声明确实可以悬挂,而类声明则不会。 因此,必须首先声明您的类,然后才能使用它,否则将引发类型为ReferenceError的异常。

类声明


定义类的第一种方法是使用类声明。 为此,请使用class关键字并指定类名称(在示例中为“ myClass”)。
 class myClass{ constructor(height, width) { this.height = height; this.width = width; } } 

定义类的第二种方法是类表达式。您可以创建命名和无名表达式。在第一种情况下,类表达式的名称在类的本地范围内,并且可以通过类本身的属性而不是其实例获取。
 //  var myClass = class { constructor(height, width) { this.height = height; this.width = width; } }; //  var myClass = class myClass { constructor(height, width) { this.height = height; this.width = width; } }; 

类表达式与类声明一样会遇到相同的问题!

类声明主体和类表达式以严格模式执行。
严格模式会更改运行时的语法和行为。
更精确地说,严格模式具有以下特征:
  • 将错误转换为异常
  • 在某些情况下使用名称来简化变量计算的更改;
  • , eval arguments;
  • , «» JavaScript;


  1. .
  2. .
  3. , , .
  4. ( ).
  5. , , . , .
  6. . .
  7. 禁止使用八进制数字的语法。
  8. 禁止使用原始值设置属性。

使用变量
简化工作严格模式简化了变量名称与代码中定义位置之间的比较。
  1. 禁止使用with。with的问题在于,在运行时,块内的任何名称都可以引用正在处理的对象的属性,也可以引用周围(甚至全局)上下文中的变量-不可能事先知道。已经存在一个简单的替代方法-将对象分配给具有短名称的变量,然后将所需的属性作为此变量的属性进行访问。
  2. 严格模式下的eval()不会向周围的上下文中添加新变量。
  3. 禁止删除简单名称。

简化eval和参数的使用
严格模式减少了参数和eval行为中的奇数,这两者都将一定量的魔术混合到常规代码中。因此,eval添加或删除变量并更改其值,而arguments变量可能会为其索引属性感到惊讶,这些属性是命名函数参数的引用(同义词)。
  1. 关键字eval和arguments不能被覆盖或修改。
  2. arguments对象的字段不与命名的函数参数关联,而是它们的值的重复副本。
  3. 不支持arguments.callee属性。在常规代码中,arguments.callee属性引用函数本身,以调用创建arguments对象的方式。

“安全” JavaScript
一些网站为用户提供了编写JavaScript的能力,这些JavaScript将代表其他用户在该网站上执行。在浏览器中,JavaScript可能有权访问私人信息,这是JavaScript中的安全漏洞。
  1. 传递给函数的值不会在严格模式下强制转换为对象。
  2. 通过基本ECMAScript扩展“运行” JavaScript堆栈是不可能的。
  3. 在函数中,arguments属性不再提供对在函数内部创建的变量的访问。

您可以查看ECMAScript 5.1 规范以了解有关严格模式的更多信息。
还有Mozilla的文档

建设者


构造函数是一种特殊方法,用于创建和初始化使用该类创建的对象。
 class Student { constructor(name) { this.name = name; } } var robert = new Student('Robert'); console.log(robert.name); // Outputs 'Robert' 

从类创建新对象时,将启动构造函数(),这是初始化对象所必需的。

在称为构造函数的类中,只能有一个方法。如果该类包含多个构造函数,则将引发SyntaxError异常。

可以在构造函数中使用super关键字来调用父类的构造函数。

如果未定义构造函数方法,则将使用默认构造函数。
对于基类,默认构造函数为:
 constructor() {} 

对于派生类,默认构造函数为:
 constructor(...args) { super(...args); } 


方法


方法声明语法:
 var obj = { property([parameters]) {}, get property() {}, set property(value) {}, * generator() {} }; 

速记发生器方法
 var obj = { * g() { var index = 0; while(true) yield index++; } }; var it = obj.g(); console.log(it.next().value); // 0 console.log(it.next().value); // 1 


除生成器方法外,所有方法定义都不能是构造函数,如果尝试实例化它们,则会抛出TypeError。

计算的属性名称
 var obj = { ["foo" + 2](){ return 2; } console.log(obj.foo2()); // 2 }; 


static关键字为类定义静态方法。静态方法在不实例化其类的情况下被调用,并且不能在该类的实例上被调用。

getter和setter的语法
 class Student { constructor(name) { this.name = name; } get Name() { return this.name; } set Name(newName) { if(typeof(newName) != "string") throw new Error("Name is not a string!"); else this.name = newName; // Robert } } var robert = new Student('robert'); robert.Name = "Robert"; console.log(robert.Name); 

  • setter-验证书面参数所必需(如上例所示)
  • getter-需要获取属性(尽管可以直接获取)。不能有参数

ES6中没有内置封装,但是您可以自己组织它。 例如,像这样:

 var Student = (function () { let privateProps = new WeakMap(); class Person { constructor(name, Age) { this.name = name; // public privateProps.set(this, {age: Age}); // private } get Age() { return privateProps.get(this).age; } set Age (newAge) { privateProps.set(this, {age: newAge}); } } return Person; })(); var robert = new Student('Robert', 19); robert.Age = 20; console.log(robert.Age); // 20 


传承


extend关键字用于类声明和类表达式中,以创建作为另一个类的子类的类。

 class Person { constructor (age) { this.age = age; } sayAge () { return this.age; } } class Student extends Person { constructor (name, age) { super(age); this.name = name; } sayFull () { return `Hello my name is ${this.name} and I'm ${super.sayAge()} years old`; } } var robert = new Student("Robert", 19); console.log(robert.sayFull()); // Hello my name is Robert and I'm 19 years old 


在构造函数中,super()关键字用作调用父构造函数的函数。必须在构造函数主体中第一次调用this关键字之前调用它。super关键字也可以用于调用父对象的函数。

当您在子类中重写父类的方法时,默认情况下将调用子类的方法,但是您可以使用super()函数显式调用父类的方法。
 class obj { constructor(name){ this.name = name; } displayName(){ return this.name.length; } } undefined class obj_2 extends obj { constructor(name) { super(name); } displayName() { //     return [this.name, super.displayName()]; } } var Obj = new obj_2("obj_2"); console.log(Obj.displayName()); // Array [ "obj_2", 5 ] 


使用extends扩展内联对象
此示例扩展了内联Date对象。
 class myDate extends Date { constructor() { super(); } getFormattedDate() { var months = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]; return this.getDate() + '-' + months[this.getMonth()] + '-' + this.getFullYear(); } } 


承诺


Promise对象用于延迟和异步计算。

承诺可以处于三种状态:
  • 待定:初始状态,未完成,未被拒绝。
  • (fulfilled): .
  • (rejected): .

(pending), (fulfilled), (), (rejected), . , then. ( , , .. « », , , DOM.)

Promise.prototype.then() Promise.prototype.catch() , , .
图片

(promise)
使用new关键字及其构造函数创建Promise对象。Promise构造函数将一个称为执行程序函数的参数作为参数。此函数应接受两个回调函数作为参数。当异步操作成功完成并返回其执行结果作为值时,将调用第一个(解析)。当操作失败时,将调用第二个回调(拒绝),并返回一个指示失败原因的值,通常是一个错误对象。
 const myPromise = new Promise((resolve, reject) => { //   ,    : resolve(someValue); //   //  reject("failure reason"); //  }); 

具有两个参数的函数对象resolvereject使诺言成功;第二个拒绝它。

要为函数提供promise功能,您只需要在其中返回Promise对象。
 function myAsyncFunction(url) { return new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); xhr.open("GET", url); xhr.onload = () => resolve(xhr.responseText); xhr.onerror = () => reject(xhr.statusText); xhr.send(); }); } 

使用。然后附加执行和拒绝处理程序。

方法
  • Promise.all(可迭代)-等待所有承诺的执行或拒绝。返回一个承诺,该承诺将在所有promise迭代执行后执行。如果任何承诺被拒绝,Promise.all也将被拒绝。
  • Promise.allSettled(可迭代)-等待所有收到的诺言完成(执行和拒绝)。返回所有接收到的承诺完成(执行或拒绝)时执行的承诺,其中包含接收到的承诺执行结果的数组。
  • Promise.race(可迭代)-等待执行或拒绝任何收到的承诺。返回一个承诺,该承诺将与.iterable中第一个已执行或被拒绝的承诺的执行结果一起执行或拒绝。
  • Promise.reject(原因)-返回由于原因而被拒绝的承诺。
  • Promise.resolve(值)-返回使用结果值执行的承诺。

无极原型
  • catch(onRejected)-添加了一个回调函数来处理对诺言的拒绝,如果调用了传回值,则返回一个新的诺言,如果作出了诺言,则返回原始的解析值。
  • 然后(onFulfilled,onRejected)-添加一个Promise履行和拒绝处理程序,并返回一个新的Promise,并使用被调用的处理程序的值执行;如果未处理Promise(即对应的onFulfilled或onRejected处理程序不是函数),则返回原始值。


创建一个异步http请求:
 const URL = "https://getfestivo.com/v1/holidays?api_key=f8f42551-eb66-49d2-bcba-b8e42727ddfb&country=US&year=2019"; //  API      function asyncHttpRequest (url) { return new Promise((resolve, reject) => { //  promise if (url == undefined) //     url reject(new Error("Expected url and received nothing")); else { resolve(() => { fetch(url).then((response) => { //   return response.json(); //    JSON   }).then((myJson) => { return(console.log(myJson)); //      }); }); } } );} asyncHttpRequest(URL).then((result) => result(), (error) => console.log(error)); 



您可以在官方文档以及Mozilla 文档中获得有关诺言的更多示例和信息

迭代器


处理集合中的每个项目都是非常常见的操作。 JavaScript提供了几种遍历集合的方法,从简单的for循环到map(),filter()和数组理解。迭代器和生成器将枚举的概念直接实现到语言的核心,并提供了一种机制来设置循环的行为。

如果对象可以一次访问一个集合的元素,同时跟踪其在此序列中的当前位置,则它是一个迭代器。在JavaScript中,迭代器是提供next()方法的对象,该方法返回序列的下一个元素。此方法返回具有两个属性的对象:done和value。

创建迭代器对象后,可以通过调用next()方法显式使用它。

可迭代-这是一个对象,其内容可以被迭代。
可迭代对象与不可迭代对象的不同之处在于,它具有一种特殊的方法,该方法返回使用特殊符号访问的对象:Symbol.iterator
 Iterable { [Symbol.iterator]() } 

返回该方法的对象正式称为迭代器。
迭代器只有一个next()方法
 Iterator { next(); } 

它返回一个具有完成的两个属性和值的对象(我们称之为itreratorResult)
 IteratorResult { done, value } 

完成表示在搜索的序列中是否仍然有一个值,并且value包含序列的下一个元素。


初始化之后,可以调用next()方法来逐个访问对象中的键值对。

如果对象定义了枚举值的方法(例如,如何在for..of构造中枚举值),则该对象是可迭代的。默认情况下,某些内置类型(例如Array或Map)是可迭代的,而其他类型(例如Object)则不可迭代。

要实现迭代,对象必须实现iterator方法,这意味着它(或原型链中的对象之一)必须具有称为Symbol.iterator的属性。

这是标准迭代器的外观:
 function makeIterator(array){ var nextIndex = 0; return { next: function(){ return nextIndex < array.length ? { value: array[nextIndex++], done: false } : { done: true }; } } } 


发电机


生成器是一种特殊的函数,其功能类似于迭代器工厂。如果函数包含一个或多个yield语句并使用function *语法,则该函数将成为生成器。

生成器是一种新型函数,可以暂停其执行并返回中间结果,然后在以后恢复执行。

我们来看一个执行一些数学运算并返回结果的常规函数​​:
 function myFunction (a) { a = a*2; a = a - 1; return a; } console.log(myFunction(5)); // 9 

现在来看一个类似的生成器函数:
 function* generator(a) { a = a*2; yield a; a = a - 1; yield a; } var it = generator(5); console.log(it.next().value); // 10 console.log(it.next().value); // 9</i> 

如前所述,生成器可以暂停执行并返回中间结果。此示例显示,在第一次调用时,该函数好像在第一个断点yield上挂起其执行,并返回第一个表达式的结果。在第二个调用中,该函数从上一个断点继续并移至下一个断点,并返回下一个表达式的结果。

函数生成器为编写复杂的顺序函数提供了强大的工具。

生成器按需计算其收益表达式的结果,这使它们可以有效地处理具有高计算复杂度的序列,甚至无限序列。

next()方法还采用一个可用于更改生成器内部状态的值。传递给next()的值将被视为暂停生成器的最后一个yield表达式的结果。

您可以通过调用生成器的throw()方法并传递应作为参数抛出的异常值来强制生成器抛出异常。将从生成器的当前暂停上下文中抛出此异常,就像当前暂停的yield语句是throw语句一样。

如果在处理引发的异常期间未发生yield语句,则该异常将通过throw()调用传递到上面,并且对next()的后续调用的结果将是done属性等于true。

生成器具有返回(值)方法,该方法返回给定值并停止生成器。

记号


Symbol是一种原始数据类型,其实例是唯一且不可变的。

在JavaScript运行时中,通过调用Symbol()函数创建一个“ symbol”值,该函数动态创建一个匿名且唯一的值。唯一合理的用途是保存字符,然后使用存储的值创建对象的属性。

当字符用作属性分配中的标识符时,该属性(例如,字符)是匿名的;而且也不可数。由于该属性不可计算,因此不会在“ for(... in ...)”循环中显示,并且由于该属性是匿名的,因此不会在“ Object.getOwnPropertyNames()”结果数组中显示。可以使用创建它的符号的初始值或通过遍历结果数组“ Object.getOwnPropertySymbols()”来访问此属性。


因此,您可以创建一个character属性:
 var user = { name: "Alex", [Symbol("password")]: "12hsK3I" } 

要获取字符对象数组,请使用Object.getOwnPropertySymbols(obj)属性;
要访问代码中的任何位置,请使用Symbol.for()和Symbol.keyFor()方法,

有关Sumbol数据类型的更多信息,请参见官方文档以及Mozilla 文档

Source: https://habr.com/ru/post/zh-CN460741/


All Articles