ECMAScript6

简介

ES6目标,让JavaScript变成一个企业级的开辟言语,不单单议限定与前端页面的脚本言语。

范例(Standard): 用于定义与其他事物辨别的一套划定规矩
完成(Implementation): 某个范例的详细实行/实在实践

编译

服务端运用
babel 编译

构建东西fis运用
插件:fis-parser-babel2 编译ES6

fis.match('**.ts', {
    
    parser: fis.plugin('babel2'),
    
    rExt: '.js'
    
});

TypeScript与babel编译有辨别:

比方:对一个类的编译TypeScript编译的效果是一个闭包类,babel编译的效果是一个安全类.

function _classCallCheck( instance, Constructor ) { 
    if (!(instance instanceof Constructor)) { 
        throw new TypeError("Cannot call a class as a function"); 
    } 
}

var Person = function Person() {

    _classCallCheck(this, Person);

};

浏览器端编译
traceur库来编译.

traceur库,引入两个库:traceur.jstreaceur-bootstrap.js

写<script>的ES6中,须要指定type范例为module
注重:<script> 须要写在引入库的后边。

<script src="../lib/traceur.js" type="text/javascript" charset="utf-8"></script>
<script src="../lib/traceur-bootstrap.js" type="text/javascript" charset="utf-8"></script>


<script type="module">
    
    class Person {
        
    }
    
    console.log(Person);
    
</script>


let&const

let

let声明一个块级作用域,而且可以初始化该变量。用法与var相似。只能在地点的代码块内有用。

块作用域:{}构成的一个代码库处的作用域叫做块作用域。

let 许可吧变量的作用域限定在块级域中。与var 差别的是:var声明变量要么是全局的,要么是函数级的,而没法是块级的。

典范运用:for轮回中的计数器
let定义的变量,会在块作用域保留下来,接见的就是当前轮回的变量值。

for ( let j=0; j<4; j++ ) {
}

console.log(j); // error 报错。
for(let i = 0; i < 5; i++){
  setTimeout(function(){
      console.log(i);
  }, i * 100);
}


作用域划定规矩

用let定义的变量的作用域是定义它们的块内,以及包含在这个块中的子块
与var辨别,是不是可以有块级观点,是不是有存在变量提拔

function test () {
    
    let a = 10;
    
    if ( true ) {
        
        let a = 20;
        
        console.log(a); // 20
        
    }
    
    console.log(a); // 10
    
}

test();

不存在变量提拔

console.log(b); // undefined
console.log(a); // 报错ReferenceError

let a = 10;
var b = 10;

function foo(){

  a = 20;  // 报错 ReferenceError
  console.log(a);
  
  let a = 10;
  console.log(a);
  
}
foo();

let 的暂存死区

在同一个函数或同一个作用域中的let反复定义一个变量将引入TypeError

注重:switch中声明的变量。

if ( true ) {
    
    let a;
    
    let a; // TypeError thrown.
    
}

假如块中存在let 和const。 通常在声明之前就运用这些变量,就会报错。
let声明之前,该变量都是不可用的。称之为:暂时性死区(temproal dead zone简称 TDZ)

if (true) {
  // TDZ最先
  a = 10; // ReferenceError
  console.log(tmp); // ReferenceError

  let a; // TDZ完毕
  console.log(tmp); // undefined

  a = 100;
  console.log(tmp); // 100
}

ES6中的TDZ 像是运转时的搜检而不是语法声明上的观点.

if(true){
    
    setTimeout(function(){
        
        console.log(x); // 1
        
    });
    
    let x = 1;
    
}

let特征:

  • 具有块级作用域
  • 没有变量提拔
  • 不许可反复声明
  • 具有暂时性殒命区

为了不动身殒命区,必需,变量先声明,后运用的划定。
let声明的全局变量并非全局对象的属性
let声明的变量晓得掌握流抵达该变量被定义的代码行时才会被装载,所以在抵达之前会运用该变量会触发毛病,也就是所说的暂时性殒命区。没有分为预剖析阶段。

块级作用域的意义:
ES5中,只需全局作用域和函数作用域,没有块级作用域。

瑕玷:
1:内存变量可以会掩盖外层变量。
2:用来计数的轮回变量走漏为全局变量。(轮回内变量过分同享)

const

const声明一个只读的常量。 一旦声明,常量的值就不可变动。
意味着,const一旦声明常量,就必需马上初始化,不可留到今后赋值。

语法:const key = value;

在定义常量的前面,不能接见到常量,因而平常都将常量定义在文件的最前面。
比方:require() 模块的时刻运用。

const http = require('http');

常量不能被反复定义,为了保证常量定义运用的时刻的安全性。

const 和 let 的辨别:
const具有let的一切特征,比let越发严厉,不可以被反复定义(赋值)。

const 只是保证变量名指向的地点稳定,并不保证该地点的数据稳定。所以将一个对象声明为常量必需异常警惕。


const foo = {};

foo.k1 = 100;

console.log( foo.k1 );

foo = {}; // TypeError: "foo" is read-only
// 常量foo 贮存的是一个地点,这个地点指向一个对象。不可变的只是这个地点,即不能把foo指向另一个地点,然则对象本身是可变的,所以依旧可以为其增加新的属性。

Objcet.freeze()
作用:凝结对象(不可为对象增加属性和和要领)
参数:被凝结的对象

const foo = {}
Object.freeze(foo);


// 通例情势时,下面一行不起作用, 疏忽增加 
// 严厉情势时,该行会报错
foo.k1 = 100;

console.log(foo);

解构赋值

组织的作用是可以疾速取得数组或对象当中的元素或属性,而无需运用arr[x]或许obj[key]等传统体式格局举行赋值.

数组的组织赋值

解构:从数组和对象中提取值,对变量举行赋值。

基础用法:

let [a, b, c] = [1, 2, 3]; // 从数组中提取值,根据对应位置,对变量赋值。
// 这类写法,本质上属于“情势婚配”。 只需等号双方的情势雷同,摆布的变量就会给予对应的值。

let [foo, [[bar], baz]] = [1, [[10], 100]];

let [x, y, ...z] = ['a', 'b', 'c', 'd'];

console.log(x,y,z); // a b ["c", "d"]

假如解构不胜利,变量值为undefiend。

let [d] = []; // undefined
let [e, f] = [1]; // 1 undefined

不完整解构: 等号左侧的情势,只婚配一部份等号右侧的数组。

let [x, y] = [1, 2, 3];
console.log(x, y); // 1  2

let [a, [b], c] = [1, [2, 3], 4];

console.log(a, b, c); // 1 2 4

等号的右侧不是数组,(严厉的说,不是可遍历的组织),会报错。

// 报错
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
// 转为对象今后不具有Iterator接口(前面5个表达式), 本身就不具有Iterator接口(末了一个表达式) 

只需某种数据组织具有Iterator接口,都可以采纳数组情势的解构赋值。 (比方:函数实行以后的返回值)

默许值
解构赋值许可设置默许值

let [a = 100] = [];

console.log(a); // 100

ES6内部运用严厉相称 运算符(===),推断一个位置是不是有值。假如一个数构成员不严厉即是undefeind,默许值不会见效。

let [a = 1] = [undefined];
let [b = 10] = [null];
let [c = 100] = [NaN];

console.log(a, b, c); // 1 null NaN

假如默许值是一个表达式,这个表达式是惰性求值(只需在用到的时刻才会求值)。

function fn () {
    console.log('a');
}

let [x = fn()] = [1];

console.log(x); // 1 
// fn(); 函数不会实行

默许值可以援用别的解构赋值的变量
默许值可以援用解构赋值的别的变量,但该变量必需已声明,假如不声明,将会报错。

let [x = 1, y = x] = []; // x = 1  y = 1
let [x = y, y = 1] = []; // ReferenceError 
// x用到默许值y时,y还没有声明。

最为常常使用的处所是:函数参数的arguments类数组对象的解构赋值。

对象的解构赋值

对象的解构与数组有一个重要的差别的地方,数组的元素是按序次排序,变量的取值由它的位置决议的,而对象的属性没有序次,变量必需与属性同名,才取到准确的值。


let {a, b} = {b: 10, a: 100}; 

console.log(a, b); // 10  100

let { c } = {d: 1000, e: 100 }
console.log(c); // undefined

对象的解构赋值的内部机制:先找到同名属性,然后再赋值给对应的变量。真被赋值的是后者,而不是前者。

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

console.log(baz); // aaa
console.log(foo); // ReferenceError
// 被赋值的是变量baz,而不是情势foo

默许值

默许值见效的条件:对象的属性值严厉即是undefined。

let {x = 3} = {x: undefined}
// x = 3;

let {y = 10} = {y: null}

console.log(x, y); // 3 null

假如解构失利,变量值即是undefined

字符串的解构赋值

字符串的解构赋值本质:字符串被转为类数组对象,类数组对象中有length属性,可以有Iterator接口,可以被遍历。

const [a, b, c, d, e] = 'hello';

console.log(a, b, c, d, e); // h e l l o

数值和布尔值的解构赋值

须要指定包装对象toString
解构划定规矩:等号右侧的值不是对象,就先将其转为对象。 undefind 和 null 没法转为对象,对其两者解构赋值,都邑报错。

let {toString: s} = 10;

console.log( s === Number.prototype.toString ); // true

console.log(s);  // function toString() { [native code] }

let { toString: t } = true;

console.log(t); // function toString() { [native code] }

函数参数解构赋值

可以解构赋值,可以运用默许值


[[1, 2], [3, 4]].map( ([a, b]) => a + b ); // 3 7
[[, 2], [, 4]].map(function ( [a = 10, b] ) {
    return a + b;
}); 

圆括号题目

关于编译器来讲,一个式子究竟是情势,,照样表达式,没有办法从一最先就晓得,必需剖析到(或剖析不到)等号才晓得。
题目:情势中涌现的圆括号怎样处置惩罚。
剖析划定规矩:只需有可以致使解构的歧义,就不得运用圆括号。

发起:只需有可以,就不要再情势中安排圆括号。能不运用,就不运用圆括号。

不能运用圆括号的状况

变量声明语句中,不能带有圆括号

// 悉数报错
var [(a)] = [1];

var {x: (c)} = {};
var ({x: c}) = {};
var {(x: c)} = {};
var {(x): c} = {};}

var { o: ({ p: p }) } = { o: { p: 2 } };
// 都是变量声明语句,情势不能运用圆括号。


函数参数中,情势不能带有圆括号。

// 报错
function f([(z)]) { return z; }    

赋值语句中,不能将全部情势,或嵌套情势中一层,放在圆括号当中。

// 悉数报错
({ p: a }) = { p: 42 };
([a]) = [5];

可以运用圆括号的状况:
赋值语句的非情势部份,可以运用圆括号。

[(b)] = [3]; // 准确  // 情势是取数组的第一个成员,跟圆括号无关
({ p: (d) } = {}); // 准确 // 情势是p,而不是d;
[(parseInt.prop)] = [3]; // 准确 // 情势是取数组的第一个成员,跟圆括号无关

用处

交流变量的值

[x, y] = [y, x]

从函数返回多个值

函数只能返回一个值,假如要返回多个值,只能将它们放在数组或对象里返回。

// 返回一个数组

function example() {
  return [1, 2, 3];
}
var [a, b, c] = example();

// 返回一个对象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
var { foo, bar } = example();

函数参数定义

将一组参数与变量名对应。

// 参数是一组有序次的值
function f([x, y, z]) { ... }
f([1, 2, 3]);

// 参数是一组无序次的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1});

提取JSON数据

提取JSON对象中的数据

函数参数的默许值

遍历Map组织

输入模块的指定要领

加载模块时,每每须要指定输入那些要领。

const { SourceMapConsumer, SourceNode } = require("source-map");

String的扩大

satrtsWith

str.starsWith(str1, num);

推断字符串以指定参数开首
参数1:开首的字符
参数2:可选,指定最先查找的索引位置
返回布尔值

endWith

str.endWith(str1, num);

推断字符串以指定参数完毕
参数1:完毕的字符子串
参数2:可选,指定最先查找的索引位置
返回布尔值

includes


str.includes(str1, num);

推断指定的参数字符串是不是包含在字符串中。
参数1:被查询的字符串
参数2:可选,从那里最先查找索引位置。
返回布尔值

标签模板

“可以紧跟一个函数名后边,该函数将被挪用来处置惩罚这个模板字符串。 称之为:“标签模板”(tagged template);


alert`123`;
alert(123);  // 同等

标签模板本质并非模板,而是函数的挪用的一种特别情势。“标签”指的就是函数,紧跟在背面的模板字符串就是它的参数。

假如模板字符内里有变量,就不在是简朴的挪用,而是会将模板字符串先处置惩罚成多个参数,再挪用函数。

模板字符串

语法:${表达式}
须要经由历程“来声明字符串,才会见效。
假如运用''单引号声明没有效果。并不会剖析模板中的表达式。

//let num = `十`;
let num = `5`;
let intro = `<h1>笑一笑,${5 * 2}幼年</h1>`;

repeat

反复字符串
参数:指定反复的次数


let num = '10';

let intro = `<h1>笑一笑,${num * 2}幼年</h1>`;

let introT = intro.repeat(2);

console.log(intro);

console.log(introT);

raw

返回原始字符串,该要领不会将字符串中的转义字符转义
这个要领特别,不须要运用()挪用.
是String底下的一个要领,直接经由历程String挪用即可。


console.log('success \n 1');

let str = String.raw`success \n 1`;

console.log(str);

Number的扩大

ES6在Number对象上,供应了Number.isFinite() 和 Number.isNaN();两个要领。
用来搜检Infinite和NaN这两个特别值。

isFanite();

搜检是不是是作为数字存在,关于不存在或许是NaN返回值为:false,关于数字返回值为:true

Number.isFinite(15); // true
Number.isFinite(0.8); // true
Number.isFinite(NaN); // false
Number.isFinite(Infinity); // false
Number.isFinite(-Infinity); // false
Number.isFinite('foo'); // false
Number.isFinite('15'); // false
Number.isFinite(true); // false

// 完成体式格局
(function (global) {
  var global_isFinite = global.isFinite;

  Object.defineProperty(Number, 'isFinite', {
    value: function isFinite(value) {
      return typeof value === 'number' && global_isFinite(value);
    },
    configurable: true,
    enumerable: false,
    writable: true
  });
})(this);

isNaN();

当参数是NaN的时刻,才返回true,别的状况都返回false。

Number.isNaN(NaN) // true
Number.isNaN(15) // false
Number.isNaN('15') // false
Number.isNaN(true) // false
Number.isNaN(9/NaN) // true
Number.isNaN('true'/0) // true
Number.isNaN('true'/'true') // true

// 完成体式格局
(function (global) {
  var global_isNaN = global.isNaN;

  Object.defineProperty(Number, 'isNaN', {
    value: function isNaN(value) {
      return typeof value === 'number' && global_isNaN(value);
    },
    configurable: true,
    enumerable: false,
    writable: true
  });
})(this);

与传统的全局要领isFinte()要领isNaN()的辨别:
传统要领先挪用Number()将非数值的值转为数值,再举行推断。
Number.isFinte()和isNaN();只对数值有用,非数值一概返回false.

parseInt&parseFloat

ES6将全局要领parseInt();和parseFloat();要领 移植到Number对象上,行动完整坚持稳定。

目标:逐渐削减全局性要领,是的言语逐渐模块化。

isInteger

当参数是正整数,负整数,0,-0,的时刻返回值为:true。别的状况下返回值为:false
在JavaScript内部,整数和浮点数运用一样的存储要领,所以3和3.0被视为同一个值。

Math的扩大

sign

Math.sign();用来推断一个数究竟是整数,负数,照样零。
返回值:

  • 参数为整数,返回+1
  • 参数为负数,返回-1
  • 参数为0 ,返回0
  • 参数为-0,返回-0
  • 参数为别的值,返回NaN

    Math.sign(”); // NaN
    Math.sign(‘a’); // NaN
    Math.sign(NaN); // NaN
    Math.sign(false); // NaN
    Math.sign(undefined); // NaN
    Math.sign(0); // 0
    Math.sign(-0); // -0
    Math.sign(-2); // -1
    Math.sign(+2); // 1

// 模仿 Math.sign(); 要领
Math.sign = Math.sign || function ( x ) {
    
    x = +x;
    
    if ( x === 0 || isNaN(x) ) {
        return x;
    }
    
    return x > 0 ? 1 : 1;
    
}

trunc

Math.trunc(); 用于去除一个数的小数部份,返回 整数部份。

非数值,Math.trunc()内部先运用Number();将其转为数值。

Math.trunc(123.456); // 123

关于空值和没法截取整数的值,返回NaN

Math.trunc(NaN); // NaN
Math.trunc('hello'); // NaN

// 模仿Math.trunc();
Math.trunc = Math.trunc || function ( x ) {
    return x < 0 ? Math.ceil(x) : Math.floor(x);
}    

Array的扩大

form

作用:将类数组对象转化成数组对象
参数1:类数组对象
参数2:可选,处置惩罚的回调函数。可以处置惩罚类对象每一个成员
该回调函数中参数1:value值,(类数组的成员), 参数2:索引值。返回值会保留终究效果,假如没有返回值,那末from函数会返回由undefined构成的一个新数组

假如是转一个真正的数组,Array.from();会返回一个如出一辙的新数组。
更常常的运用时:arguments 和 猎取的DOM元素。

// 类数组对象
let arrayLike = {
    0: 'a',
    1: 'b',
    length: 2
}

// ES5的写法
let arr1 = [].slice.call(arrayLike); 

// ES6的写法
let arr2 = Array.from(arrayLike);

console.log(arr1, arr2); // ['a', 'b']['a', 'b']  
let arrayLike = {
    0: 'a',
    1: 'b',
    length: 2
}

// ES6的写法
let arr2 = Array.from(arrayLike, function ( value, index ) {
    
    return value + '-xixi';
    
});

of

Array.of();将一组值,转为数组。
返回值:返回参数值构成的数组,假如没有参数,就返回一个空数组。

作用:填补数组组织函数Array()的不足。因为参数个数的差别,会致使Array()的行动有所差别。
Array()假如是一个参数,则示意当前数组的长度。假如是二个或二个以上,则示意数构成员。

Array.of(1, 2, 3, 'xixi');

Array.of();基础上可以用来替换Array()或new Array(); 而且不存在因为参数差别而致使的重载题目。

Array.of() // []
Array.of(undefined) // [undefined]
Array.of(1) // [1]

// 模仿Arraay.of();要领
function ArrayOf () {
    return [].slice.call(arguments);
}

find

find();要领和findIndex();要领
find();
作用:猎取第一个相符条件的数构成员。
参数:回调函数。一切的数构成员一次实行该回调函数。晓得找出一个返回值为true的成员。假如没有相符条件的成员,则返回false。
回调函数中的参数: 当前value值,当前索引值index(可选), 原数组arr(可选)

[1, 2, 23, 10].find( (n) => n > 10 ); // 23
[1, 2, 3].find( ( value, index, arr ) => value < 2  ) // 1

findIndex();
作用:返回第一个相符条件的数构成员的索引值,假如一切成员都不相符条件,则返回 -1.
参数:和find();参数一样是一个回调函数。

['cyan', 'pink', 'tan', 'red'].findIndex( (value, index, arr) => Object.is('tan', value) );

提出的处理题目:
indexOf();没法检测出成员中是不是有NaN

[NaN].indexOf(NaN);  // -1

findIndex();搭配 Object.is(); 可以检测出来

[10,NaN].findIndex(  (value) => Object.is(NaN, value) ); // 1

fill

运用给定值,添补一个数组。

参数1:添补的值
参数2:可选,添补的肇端位置。
参数3: 可选,添补的完毕位置。

keys

keys() & values(); & entrices();

keys();
猎取数组一切成员的索引值。
返回的是一个迭代器对象。
须要经由历程 for-of遍历数组迭代器

let colors = ['cyan', 'pink', 'tan', 'red'];

let Idx = colors.keys();

console.log( Idx );  // ArrayIterator {}

for ( let index of Idx ) {
    
    console.log(index);
    
}

values();
猎取一切成员的值,返回一个数组迭代器对象。

let colors = ['cyan', 'pink', 'tan', 'red'];

let vals = colors.values();

console.log( vals );  // ArrayIterator {}

for ( let val of vals ) {
    
    console.log(val);
    
}

entries();
对键值对的遍历。

将数构成员的索引值以及数构成员的值,保留在一个新数组中。

let colors = ['cyan', 'pink', 'tan', 'red'];

let entri = colors.entries();

console.log(entri);

for ( let entris of entri ) {
    
    console.log( entris );
    
}
// 输出:
// [0, "cyan"]
// [1, "pink"]
// [2, "tan"]
// [3, "red"]    

假如不运用for-of遍历,可以手动挪用遍历器对象的next();要领,举行遍历。

let colors = ['cyan', 'pink', 'tan', 'red'];

let entri = colors.entries();

console.log( entri.next().value ); // [0, "cyan"]
console.log( entri.next().value ); // [1, "pink"]
console.log( entri.next().value ); // [2, "tan"]
console.log( entri.next().value ); // [3, "red"]   

// next();要领返回:Object {value: Array[2], done: false} 
  

空位

数组的空位:数组的某一个位置没有任何值。
比方:Array组织函数返回的数组都是空位。

空位不是undefined,一个位置的值即是undefined,依旧是有值的。空位是没有任何值

注重:空位不是undefiend,一个位置的值即是undefeind。依旧是有值。空位是没有任何值。

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false
// 第一个数组的0号位置是有值的,第二个数组的 0 号位置没有值。

ES5中关于空位的不一致:

  • forEach(), filter(), every() ,some()都邑跳过空位。
  • map()会跳过空位,但会保留这个值
  • join()和toString()会将空位视为undefined,而undefined和null会被处置惩罚成空字符串。

    // forEach();
    [,’a’].forEach((x,i) => console.log(i)); // 1

    // filter();
    [‘a’,,’b’].filter(x => true) // [‘a’,’b’]

    // every();
    [,’a’].every(x => x===’a’) // true

    // some();
    [,’a’].some(x => x !== ‘a’) // false

    // map();
    [,’a’].map(x => 1) // [,1]

    // join();
    [,’a’,undefined,null].join(‘#’) // “#a##”

    // toString();
    [,’a’,undefined,null].toString() // “,a,,”

ES6则明白将空位转成undeinfed
因为空位的处置惩罚划定规矩异常不一致,所以应当只管防备涌现空位。

Object的扩大

属性的简约示意

ES6许可直接写入变量和函数,作为对象的属性和要领。
在定义一个对象的时刻,假如对象的属性与属性值对应的变量名同名,可以简写属性名。


let objName = 'bar'; 
let obj1 = {objName}

console.log( obj1 ); // Object {objName: "bar"}

// 同等于
let obj2 = {objName: objName} // Object {objName: "bar"}
console.log(obj2); 

// 在对象当中,只写属性名,不写属性值,这时刻,属性值即是属性名所代表的变量。 
// 参数简写
function Person ( name, age ) {
    return {name, age} // ES6 许可直接引入变量,不必对对象增加同名属性
}

console.log( Person('cyan', 22) );  // Object {name: "cyan", age: 22}

// 同等于    
function Person(name , age) {
  return {name: name, age: age};
}

// 要领的简写
// 假如对象属性名与对象属性名对应的要领称号雷同,可以省略属性以及 function关键字, 像定义类中的要领一样定义这个属性要领。

let obj1 = {
    name: 'cyan',
    age: 22,
    sayAge: function () {
        console.log(this.age); // 22
    },
    sayName () { // ES6许可定义要领的时刻,可以省略要领对应的属性名,和 fucntion 关键字
        console.log(this.name); // cyan
    }
}

obj1.sayName();
obj1.sayAge();    

// sayName同等于
    
var obj1 = {
  sayName: function() {
    console.log(this.name);
  }
}

// 这类属性简写用于函数返回异常轻易
function getPoint() {
  var x = 1;
  var y = 10;
  return {x, y};
}

getPoint();
// {x:1, y:10}

属性名表达式

JavaScript言语定义对象的属性,有两种体式格局。

// 要领一
obj.foo = true;  // 标识符作为属性名

// 要领二
obj['a' + 'bc'] = 123; // 表达式作为属性名
// 许可定义对象时刻,对对象属性运用表达式
let a = 'num';
let b = 'ber';

let obj = {
    [a + b]: 100
}

console.log( obj );

// 表达式也可以用于要领名
let obj = {
  ['h'+'ello']() {
    return 'hi';
  }
};

obj.hello() // hi

注重:属性名表达式不能与简约示意法同时运用,会报错。


// 报错
let a = 'b';
let b = 'pink';
let color = { [a] }

console.log(color);

// 准确
let a = 'cyan';
let color = { [a]: 'pink' }

console.log(color);

要领的name属性

函数的name属性,返回函数名。
对象要领也是函数,,因而也有name属性。


let obj = {
    name: 'cyan',
    sayName() {
        return this.name; 
    }
}

console.log( obj.sayName.name ); // sayName

特别:
bind();要领制造的函数,name属性返回”bound”加上原函数的名字。
Function组织函数制造的函数,name属性返回”anonymous”.

console.log( (new Function()).name ); // anonymous

let doSomething = function () {}

console.log( doSomething.bind().name ); //bound doSomething  

is

Object.is();
作用推断两个参数是不是相称。
可以推断0-0 ,是不是相称。

ES5中,比较两个值是不是相称运用:==或许===
==瑕玷:自动转换数据范例
===瑕玷:NaN不即是本身,以及0即是-0

ES6提出“Same-value equality”(同值相称)算法.
用来比较两个值是不是严厉相称,与严厉比较运算符(===)的行动基础一致。

+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

assgin

Object.assgin();
作用:用于对象兼并。
将源对象(source)的一切可罗列属性,复制到目标对象(target)。
参数1:目标对象。
背面的参数都是源对象。

只拷贝源对象的本身属性(不拷贝继承属性),也不拷贝不可罗列的属性(enumerable: false)。

假如目标对象与源对象有同名属性,或多个源对象有同名属性,则背面的属性会掩盖前面的属性。
假如只需一个参数对象,则返回该参数对象。

let obj1 = {
    x: 1,
    y: 2
}

let obj2 = {
    a: 'a',
    b: 'b'
}

console.log( Object.assign(obj1, obj2) );

假如参数不是对象,则会先转成对象然后返回。
undefeind和null没法转成对象,作为参数,会报错。

Object.assign(2); // Number {[[PrimitiveValue]]: 2}
Object.assign(undefined) // 报错
Object.assign(null) // 报错

Object.assign();是浅拷贝,而不是深拷贝。假如源对象某个属性的值是对象,那末目标对象拷贝取得的是这个对象的援用。

let obj1 = {
    x: 1,
    y: 2
}

let obj2 = {
    a: 'a',
    b: 'b'
}

let resObj = Object.assign(obj1, obj2);

console.log( resObj );
console.log( obj1 );
console.log( resObj == obj1 ); // true
console.log( obj2 );

assign用处

为对象增加属性

class Point {
    constructor (x, y) {
        Object.assign(this,{x, y});
    }
}

let p = new Point(10, 20);

console.log(p);  // Point {x: 10, y: 20}
// 经由历程Object.assign();将x属性和y属性增加到Point类的对象实例。

为对象增加要领

Object.assign(Some.prototype, {
    someMethod1 ( arg1, arg2 ) {
        // ....
    }
    someMethod2 ( arg1, arg2 ) {
        // ....
    }
})


// 等价
Some.prototype.someMethod1 = function ( arg1, arg2 ) {
    // ....
}
Some.prototype.someMethod2 = function ( arg1, arg2 ) {
    // ....
}    


克隆对象

function clone(origin) {
  return Object.assign({}, origin);
}    
// 将原对象拷贝到一个空对象,取得了原始对象的克隆。


兼并多个对象

将多个对象兼并到某个对象,可以是空对象中(兼并以后返回新的对象)


const merge = (target, ...sources) => Object.assign({}, ...sources); 


属性遍历

ES6中共有5中可以遍历属性的要领:

  • for-in
    for-in轮回遍历对象吱声和继承的可罗列的属性(不含Symbol属性)。
  • Object.keys(obj)
    Object.keys返回一个数组,包含对象本身的(不含继承)一切可罗列属性(不含Symbol属性)
  • Oject.getOwnPropertyNames(obj);
    Object.getOwnPropertyNames(); 返回一个数组,包含对象本身的一切属性(不含Symbol属性,然则包含不可罗列属性)
  • Object.getOwnPropertySymbols(obj);
    Object.getOwnPropertySymbols();返回一个数组,包含对象本身的一切Symbol属性。
  • Reflect.ownKeys(obj);
    Reflect.ownKeys(obj);返回一个数组,包含对象本身的一切属性,不论是属性名Symbol或字符串,也不论是不是可罗列

遍历划定规矩:

  • 起首遍历一切属性为数值的属性,根据数字排序。
  • 其次遍历一切属性名为字符串的属性,根据天生时候排序。
  • 末了遍历一切属性名为Symbol值的属性,根据天生时候排序。

keys&values&entries

Object.keys();
作用: 参数对象本身的(不含继承的) 一切可遍历属性的键名。
返回数组

Object.values();
作用:参数对象本身的(不含继承的) 一切可遍历属性的键值。
返回数组

Object.entries();
作用:参数对象本身的(不含继承的) 一切可遍历属性的键值对数组。
返回数组

let obj = { a: 1, b: 2 };

console.log( Object.entries(obj) );  [ ["a", 1], ["b", 2] ]

Symbol

ES6引入Symbol的缘由:基础上防备属性名的争执。

ES6引入一种新的原始数据范例Symbol,示意举世无双的值。
它是JavaScript言语的第七种中数据范例。前六中是:Undefiend,Null,布尔值(Boolean),字符串(String),数值(Number),对象(Object)

let s = Symbol();
typeof s // symbol

Symbol值经由历程Symbol函数天生。
对象的属性名可以有两种范例,一种是:string。 一种是:Symbol。(通常属性名属于Symbol范例,就是举世无双,可以保证不会与别的属性名发作争执)

注重:Symbol函数前不能运用new关键字,不然会报错。因为:Symbol是一个原始范例的值,不是对象。因为Symbol值不是对象,所以不能增加属性。基础上,它是一种相似于字符串的数据范例。

Symbol函数可以吸收一个字符串作为参数,示意对Symbol实例的形貌,
作用:掌握台显现或转为字符串时,比较轻易辨别。

返回值不相称

注重:Symbol函数的参数只是示意对当前Symbol值的形貌,因而雷同参数的Symbol函数的返回值是不相称的。

// 没有参数
let s1 = Symbol();
let s2 = Symbol(); 

console.log(s1 == s2);  // false 

// 参数
let s3 = Symbol('a');
let s4 = Symbol('b');

console.log(s3 == s4); // false

不能与别的范例值举行运算

let sym = Symbol('My Symbol');

console.log('your symbol is' + sym); // TypeError: Cannot convert a Symbol value to a string

console.log(`your symbol is` + sym);  // TypeError: Cannot convert a Symbol value to a string

可以显现转换为String,Boolean。(注重:不可以转为数值范例)


let sym = Symbol('My Symbol');

console.log(String(sym)); 
console.log(sym.toString());

console.log(Boolean(sym));
console.log(!sym);

console.log(Number(sym)); // TypeError: Cannot convert a Symbol value to a number
console.log(sym + 2);  // // TypeError: Cannot convert a Symbol value to a number

Symbol与字符串的辨别:

  • 举世无双
  • 值不相称
  • 不可与别的范例值举行运算

作为属性名Symbol

因为每一个Symbol值都是不相称的,意味着Symbol值可以作为标识符。
用于对象的属性名,就可以保证不会涌现同名的属性。 关于一个对象由多个模块构成的模块状况,能防备某一个键被不警惕改写或掩盖。

Symbol值作为属性名时,是公然属性,而不是私有属性。


let mySymbol = Symbol('a');

// 第一种要领
let a = {};
a[mySymbol] = 'hello';

// 第二种写法
let b = {
    [mySymbol]: 'hell2'
};
// 在对象的内部,运用Symbol值定义属性时,Symbol值必需放在方括号当中。

// 第三种写法
let c = {};
Object.defineProperty(c, mySymbol, {
    value: 'hello3'
});

console.log(a[mySymbol], b[mySymbol], c[mySymbol]); 

注重:Symbol值作为对象的属性名,不能运用点语法。

let mySymbol = Symbol('a');

let obj = {};

obj[mySymbol] = 'hello';

console.log( obj[mySymbol] ); // hello
console.log( obj.mySymbol ); // undefind

定义一组常量,保证这组常量值是不相称。

log.levels = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn')
};

log(log.levels.DEBUG, 'debug message');
log(log.levels.INFO, 'info message');

消弭把戏字符串

把戏字符串:在代码当中涌现屡次,与代码构成强耦合的某一个详细的字符串或许数值。
瑕玷:不利于将来的庇护和修正。

消弭把戏字符串的要领:把它写成一个变量,或许常量。
变量或许常量即是谁人值并不重要,只需确保不会跟别的的属性争执即可。

const shapeType = {
    triangle: Symbol(),
    triangleTow: Symbol()
}

function getArea ( shape, options ) {
    
    let area = 0;
    
    switch ( shape ) {
        
        case shapeType.triangle:
            
            area = .5 * options.width * options.height;
            
            break;
            
        case shapeType.triangleTow:
            
            area = .7 * options.width * options.height;
            
            break;
            
    }
    
    return area; 
    
}

let a = getArea( shapeType.triangleTow, { width: 20, height: 20 } );
let b = getArea( shapeType.triangle, { width: 10, height: 10 } );

console.log( a,b ); // 280 , 50

属性名的遍历

Symbol作为属性名,该属性不会涌现在for-infor-of轮回中,也不会被Object.kes();. Object.getOwnProperTyNames();返回。
Symbol并非私有属性,ES6中供应Object.getOwnPropertySymbols();

Object.getOwnPropertySymbols();
作用:猎取指定对象的一切Symbol属性名。
返回一个数组。成员是当前对象的一切用作属性名的Symbol值。


let obj1 = {};
let c = Symbol('c');
let d = Symbol('d');

obj1[c] = 'cyan';
obj1[d] = 'tan';

let objectSymbol = Object.getOwnPropertySymbols(obj1);

console.log( objectSymbol ); // [Symbol(c), Symbol(d)]

Reflect.ownKeys();
作用:返回一切范例的键名,包含通例键名和Symbol键名。

let obj = {
    [Symbol('my_key')]: 1,
    enum: 2,
    nonEnum: 3
};

console.log( Reflect.ownKeys(obj) ); // ["enum", "nonEnum", Symbol(my_key)]

以Symbol值作为称号的属性,不会被通例要领遍历取得。可以为对象定义一些非私有的,但又愿望只用于内部的要领。形成一种非私有话的内部的效果。

Symbol.for(),Symbol.keyFor()

Symbol.for();
作用:运用同一个Symbol的值。
参数:一个字符串。
历程:吸收一个字符串后,搜刮有无以该参数作为称号的Symbol值。假如有,就返回这个Symbol值,不然就新建并返回一个以该字符串为称号的Symbol值。(具有登记机制,被登记的会在全局环境中供搜刮)

let s1 = Symbol.for('a');
let s2 = Symbol.for('a');

console.log( s1 === s2 ); // true

Symbol.keFor();
返回:一个已登记的Symbol范例值的key。

let s1 = Symbol.for('a');
let s2 = Symbol.for('b');
let s3 = Symbol('b');

console.log( Symbol.keyFor(s1), Symbol.keyFor(s2), Symbol.keyFor(s3) ); // a b undefined 

模块的Singleton情势

Signleton情势:指的是挪用一个类,任何时刻返回的都是同一个实例。

关于 Node 来讲,模块文件可以看成是一个类。怎样保证每次实行这个模块文件,返回的都是同一个实例呢?

很轻易想到,可以把实例放到顶层对象global。

关于Node来讲,模块文件可以看成是一个类。怎样保证每次实行这个模块文件,都是返回同一个实例呢? 可以把实例挂载到顶层对象global。


// mod.js
function A () {
    this.foo = 'hello';
}

if ( !global._foo ) {
    global._foo = new A();
}

module.exprots = global._foo;


// 加载mod.js

let mod = require('./mod.js');
console.log( mod.foo );

存在题目: 挂载到global的属性,是可写的,任何文件都可以修正。
防备这类状况,可以运用Symbol.

// mod.js
const FOO_KEY = Symbol.foo('foo');

function A () {
    this.foo = 'hello';
}

if ( !global[FOO_KEY] ) {
    global[FOO_KEY] = new A();
}

module.exprots = global[FOO_KEY];

Proxy&Reflect

Proxy概述

Proxy作用:修正某些操纵的默许行动。 在目标对象之前设置屏障,外界对该对象的接见,都必需先经由历程这层阻拦,来庇护该对象(内部的属性,状况,要领,行动等等)。(Proxy的操纵同等于在言语层面做出修正,所以属性一种“元编程”,即对编程言语举行编程)

供应一种机制,可以对外界的接见举行过滤和改写。
Proxy这个词的原意是代办,这里表达hi由它来“代办”某些操纵,可以译为“代办器”。

语法: new Proxy(代办对象, 屏障对象);

屏障的要领,比较特别,并非恣意定,只能经由历程get来猎庖代办对象的信息,set来设置原始对象的额信息。然则它们不是直接处置惩罚对象的,在处置惩罚之前会过滤一些工资操纵。屏障对象设置阻拦行动(关于每一个被代办的操纵,须要供应一个对应的处置惩罚函数,该函数将阻拦对应的操纵。)

get();
参数:target,key,receiver

set();
参数:target,key,value,receiver

let Start = {
    count: 0
}

let obj1 = new Proxy(Start, {
    
    get: function ( target, key ) {
        
        console.log(`getting ${key}!`);
        
        return target[key];
        
    },
    
    set: function ( target, key, value ) {
        
        console.log(`setting ${key}!`);
        
        return target[key] = value;
        
    }
    
});

console.log( obj1.count );

obj1.count = 1;

console.log( obj1.count );

注重:是的Proxy起作用,必需针对Proxy实例举行操纵, 而不是针对目标对象举行操纵。
假如屏障对象没有举行任何阻拦操纵,那就同等于直接经由历程原对象,操纵原对象

let a = {};
let b = {};

let proxy = new Proxy(a, b);

proxy.tag = 'javascript';

console.log(a.tag); // javascript

将Proxy对象,可以设置到Object.proxy属性上,从而到达可以从Object对象上挪用。
Proxy实例可以作为其他对象的原型对象。

// 放在object.proxy 属性上
let object = {
    proxy: new Proxy(target, handler)
}

// 别的对象的原型上
let proxy = new Proxy({}, {
    get: function ( target, property ) {
        console.log( target[property] );
        return 10;
    }
});

let obj = Object.create(proxy);

console.log(obj.time); // 10    

同一个阻拦器函数,可以设置多个操纵。

var handler = {
  get: function(target, name) {
    if (name === 'prototype') {
      return Object.prototype;
    }
    return 'Hello, ' + name;
  },

  apply: function(target, thisBinding, args) {
    return args[0];
  },

  construct: function(target, args) {
    return {value: args[1]};
  }
};

var fproxy = new Proxy(function(x, y) {
  return x + y;
}, handler);

fproxy(1, 2) // 1
new fproxy(1,2) // {value: 2}
fproxy.prototype === Object.prototype // true
fproxy.foo // "Hello, foo"

Proxy阻拦器操纵函数

关于可以设置,但没有设置阻拦的操纵,则直接落在目标对象上,根据本来的体式格局发作效果。

get()
阻拦对象属性的读取

set()
阻拦对象属性的设置

has(target, propKey)
阻拦propKey in proxy的操纵,以及对象的hasOwnProperty();
返回值:布尔值。

推断对象是不是具有某个属性时,要领才会见效。典范的操纵就是in运算符。
运用has要领隐蔽某些属性,不被in运算符发明

let headler = {
    
    has ( target, key ) {
        
        if ( key[0] === '_' ) {
            return false;
        }
        
        return key in target;
        
    }
    
}

let target = { _prop: 'aaa', prop: 'bbb' }

let proxy = new Proxy(target, headler);

console.log( '_prop' in proxy ); // false

deleteProperty(target, propKey)
阻拦delete proxy[propKey]的操纵。
返回值:布尔值。 示意是不是删除胜利。

apply(target, object, args)
参数args:目标对象的参数数组。
阻拦Proxy实例作为函数挪用的操纵,比方proxy(...ars) ,proxy.call(object, ...args), proxy,apply(...)

let target = function () {
    return 'target';
}

let handler = {
    apply: function () {
        console.log('apply');
        return 'handler';
    }
}

let p1 = new Proxy(target, handler);

console.log(p1()); // hanlder


construct(target, args)
阻拦作为组织函数挪用的操纵。 比方: new Proxy(...args)

阻拦函数和PHP中的把戏要领有雷同的道理,当肯定条件下,会触发该声明的函数。

Reflect概述

Reflect对象与Proxy对象一样
为了操纵对象而供应的新API

设想目标:

  • 将Object对象的一些显著属性言语内部的要领(比方Object.defiendProerty),放到Reflect对象上,现阶段,某些要领同时在Object和Reflect对象上布置,将来的新要领将只布置在Reflect对象上。
  • 修正某Object要领的返回效果,让其变得更合理。
  • 让Object操纵都变成函数行动
    比方: delete obj[name] 和 name in obj 的指令式操纵
  • Reflect对象的要领与Proxy对象的要领一一对应,只需是Proxy对象的要领,就可以在Reflect对象上找到对应的要领。

函数的扩大

参数的默许值

ES5的默许参数做法

假如没有if推断,参数是不是被赋值,假如没有,再即是默许值
缘由:假如参数赋值了,然则对应值是false,则该赋值就不应当起作用。 比方:挪用的时刻log(‘hello’, ”); 假如参数是空字符串,就不应当被改成默许值。


function log ( x, y ) {
    
    if ( typeof y === undefined ) {
        
        y = y || 'world';
        
    }
    
    console.log(x, y);
    
}

log('Hello'); // Hello world
log('Hello', 'hi'); // Hello hi
log('Hello', ''); //   Hello

ES6运用默许参数,直接写在参数定义的后边。
长处:
1:易浏览代码
2:利于将来的代码优化。将来的版本在对外接口中,测底拿掉这个参数,也不会致使之前的代码没法实行。

特征:参数变量时默许声明的,不能用let或const再次声明

function Point ( x, y=10 ) {
    this.x = x;
    this.y = y;
}

let p = new Point(100);
console.log(p);  // Point {x: 100, y: 10}

参数默许的位置

平常的,定义默许值的参数,应当是函数的尾参数。如许可以比较轻易看出来,究竟省略了哪些参数。

假如非尾参数设置默许值,这个参数是没法省略。(想运用默许值,设置为undefeind)

function fn ( x = 1, y ) {
    
    return [x ,y];
    
}

console.log( fn() );  // [1, undefined]
console.log( fn(2) );  // [2, undefined]
console.log( fn(undefined, 1) ); // [1, 1] // 假如传入undefeind,将触发该参数即是默许值, 
console.log( fn(null, 1) ); // [null, 1] // 假如传入null,则会输出。
console.log( fn( , 10) ); // error 
function fn2 ( x, y = 1, z ) {
    
    return [x, y, z];
    
}

console.log( fn2() ); // [undefined, 1, undefined]
console.log( fn2(2) ); // [2, 1, undefiend]
console.log( fn2(2, undefined, 3) ); // [2, 1, 3]
console.log( fn2(2, , 3) ); // error 

函数的length属性

length属性的寄义:该函数预期传入的参数个数。

指定了默许值后,length属性将失真。将返回没有指定默许参数的个数。
某个参数指定了默许值今后,预期传入的参数个数就不包含这个参数了。rest参数不会计入length属性个数中。

let len1 = (function (a) {}).length;

let len2 = (function (a = 5) {}).length; 

let len3 = (function ( a, b, c = 1 ) {}).length;  

let len4 = (fucntion (...args) {}).length;

console.log(len1); // 1
console.log(len2); // 0
console.log( len3 ); // 2
console.log( len4 ); // 0

作用域

假如参数默许值是一个变量,则该变量所处的作用域,与别的变量的作用划定规矩是一样的,即先是当前函数的作用域,然后才是全局作用域。

var x = 1;

function fn ( x, y = x ) {
    console.log(y);
}

fn(2); // 2    

假如参数默许值是一个函数
该函数的作用域是其声明时地点的作用域

let foo = 'outer';

function bar ( func = x => foo ) {
    
    let foo = 'inner';
    
    console.log( func() ); // outer
    
}

bar();
// 函数bar的参数func的默许值是一个匿名函数,返回值为变量foo。这个匿名函数声明时,bar函数的作用域还没有构成,所以匿名函数内里的foo指向外层作用域foo

运用
应用参数默许值,可以指定某一个参数不得省略,假如省略就抛出一个毛病。

function throwMsg () {
    throw new Error('error');
}

function foo ( pro1 = throwMsg()  ) {
    
    return pro1;
    
}

foo(); // 抛出毛病

可以将参数默许值设置为unfeined,表明这个参数是可以省略的。

function foo ( options = undefined ) {

}

rest参数

语法:...变量名
作用:把逗号离隔的值序列组合成一个数组

猎取过来的是数组,将制订的过剩变量放入数组中。

运用rest参数就不须要运用arugments对象

    
function add ( ...nums ) {
    
    let sum = 0;
    
    for ( let val of nums ) {
        
        sum += val;
        
    }
    
    return sum;
    
}

console.log( add(1, 2, 3) );  // 6    

注重:rest参数以后不能再有别的参数(即只能是末了一个参数)

扩大运算符

扩大运算符...
比如rest参数的逆运算。

作用:把数组或类数组对象展开成一系列用逗号离隔的值(将一个数组转为用逗号离开的参数序列).

console.log(...[1, 2, 3]);
// 1 2 3

console.log(1, ...[2, 3, 4], 5 );
// 1 2 3 4 5 

平常的,重要用于函数挪用:

function add ( x, y ) {
    
    return x + y;
    
}

let nums = [10, 20];

console.log( add(...nums) ); // 30

扩大运算符与一般的函数参数,rest参数可以合营运用,表现灵活性。

function fn ( x, y, z, n, m, ...nums ) {
    
    console.log(...nums); // 5 ,6
    
}

let args = [1, 2];

fn(-1, ...args, 3, ...[4, 5], 6);

扩大运算符的运用

兼并数组

let moreArr = [3,4];

let arr1 = [1, 2].concat(moreArr);

console.log(arr1);

console.log( [1, 2, ...moreArr] );


let arr2 = ['a', 'b'];

let arr3 = ['c', 'd'];

let arr4 = ['e', 'f'];

// ES5的写法
console.log( arr2.concat(arr3, arr4) );

// ES6的写法
console.log( [...arr2, ...arr3, ...arr4] );

与解构赋值连系

扩大运算符与解构赋值连系起来运用,用于天生数组。
注重:扩大运算符只能放在参数的末了一名。(不然将会报错)

const [first, ...rest] = [1, 2, 3, 4, 5];   
const [...butLast, last] = [1, 2, 3, 4, 5]; // SyntaxError: Rest element must be last element in array

const [first, ...middle, last] = [1, 2, 3, 4, 5];  // SyntaxError: Rest element must be last element in array


函数返回值

JavaScript的函数只能返回一个值,假如须要返回多个值,只能返回数组或对象。扩大运算符供应变通要领。

字符串

扩大运算符可以将字符串转为数组


console.log( [...'hello'] ); // ["h", "e", "l", "l", "o"]    

完成了Iterator接口的对象

任何Iterator接口对象,都可以运用扩大运算符转为真正的数组
比方:arguments对象,nodeList对象

let arrList = {
    '0': 'a',
    '1': 'b',
    '2': 'c',
    length: 3
}

console.log( [...Array.from(arrList)] ); // ["a", "b", "c"]
console.log( [...arrList] );  // TypeError: arrList[Symbol.iterator] is not a function

name属性

函数的name属性,返回该函数的属性名。
属性被浏览器支撑,到ES6才写入范例中。

ES5中匿名函数,name属性会返回空字符串。
ES6中匿名函数,name属性会返回现实的函数名

ES5,ES6中,著名的匿名函数,name属性返回具有函数名的名字

Function 组织函数返回函数实例, name 属性值为:anonymouse

let fn1 = function () {};

// ES5
console.log( fn1.name ); // ''

// ES6
console.log( fn1.name ); // fn1


const fn = function fn2 () {}

// ES5
console.log( fn.name );  // fn2

// ES6
console.log( fn.name ); // fn2

// Function 组织函数
console.log( (new Function).name ); // 'anonymouse';

箭头函数

基础用法

运用 => 定义函数
() => 表达式
参数 => 表达式

var f = v => v;
// 等价
var  f = function ( v ) {
    return v;
}

假如箭头函数须要多个参数或许不须要参数,可以运用()代表参数。

() => { 函数体 }

var fn = () => 5;

// 同等于
var fn = function () { return 5; }



var sum = (num1, num2) => num1 + num2;

// 同等于
var sum = function ( num1, num2 ) { return num1 + num2 }

箭头函数返回对象,须要在对象外加()

var getTemp = id => ({ id: id, name: 'cyan' });    

箭头函数与变量解构赋值,rest参数搭配运用

let fn = (...s) => {
    console.log(...s);
}

const full = ( first, last ) => {
    return first+ ' ' + last;
}

// 同等于
function full( first, last ) {
    return first+ ' ' + last;
}

箭头函数运用注重点

  • 函数体内的this对象,就是定义时地点的对象,而不是运用时地点的对象。
  • 不可以看成组织函数,也就是不可以运用new关键字。不然会抛出一个毛病。(names is not a constrtucor)
  • 不可以运用arguments对象,因为arguments对象不存在函数体内
  • 不可以运用yield敕令, 因而箭头函数不能作用Generator函数。

this牢固

this对象在箭头函数中,是牢固的。

this的指向牢固化,有利于封装回调函数。
this指向牢固化,并非因为箭头函数内部有绑定this的机制,现实缘由是箭头函数基础没有本身的this。致使内部的this就是外层代码块的this。恰是因为它没有this,所以也就不可以作为组织函数。

箭头函数的this永久指向定义的时刻的作用域,在各对象中定义,就指向谁人对象。
当运用call()和apply()要领变动作用于时刻,箭头函数this是没有变动胜利。

function foo () {
    
    setTimeout(() => {
        console.log( 'id:', this.id );  // 42
    },100);

    setTimeout(function () {
        console.log('id: ' ,this.id); //41
    }, 1000);
        
}

var id = 21;

foo.call({ id: 42 });
// 箭头函数致使this老是只想函数定义见效时地点的对象

对照箭头函数的setTimeout和ES5版本的一般回调函数:

// ES6
function foo () {
    
    setTimeout( () => {
        
        console.log('id:', this.id);
        
    }, 100 );
    
}

foo();

//ES5
function fn2 () {
    let _this = this;
    
    setTimeout(function () {
        console.log('id:', _this.id);
    }, 100);
}

fn2();

// fn2中清晰的说清楚明了,箭头函数内里基础没有本身的this,而是援用外层的this。 


function foo() {
    
  return () => {
      
      console.log(this); // Object {id: 1}
      
    return () => {
        
        console.log(this); // Object {id: 1}
        
      return () => {
          
          console.log(this); // Object {id: 1}
          
        console.log('id:', this.id); // id: 1

      };

    };

  };

}

var f = foo.call( {id: 1} );

f()()();   

箭头函数中不存在:this,argumetns, supernew.target.响应的指向外层函数的对应 this,argumetns, supernew.target

function foo () {
    
    console.log('args:', arguments); // args: [1, 2, 3, 4]
    
    setTimeout( () => {
        
        console.log('args:', arguments); // args: [1, 2, 3, 4]
        
    },100 );
    
}

foo(...[1, 2, 3, 4]);

箭头函数嵌套

箭头函数的嵌套:具有管道机制(前一个函数的输出是后一个函数的输入)。

let insert = (value) => ({
    
    into: (array) => ({
        
        after: (afterValue) => {
            
            array.splice( array.indexOf(afterValue) + 1, 0, value );
            
            return array;
            
        }
        
    })
});

console.log( insert(2).into([1, 3]).after(1) ); //[1, 2, 3]

尾挪用优化

尾挪用

尾挪用:指某个函数的末了一步是挪用另一函数。
尾挪用是函数式编程的重要观点。

function fn (x) {
    return g(x); // 函数的末了一步挪用函数 g() ,就是指的尾挪用
}

// 不属于为挪用的情况
function f1 ( x ) {
    let y = g(x);
    return y;    
}
// 挪用函数  g(x) 以后,另有赋值操纵。

function f2 (x) {
    return g(x) + 1; 
}
// 挪用以后另有别的操纵

function f3 ( x ) {
    g(x);
}
// f3 末了是返回 undefined


// 尾挪用不肯定要涌现在函数的尾部

function f ( x ) {
    
    if ( x > 0 ) {
        return m(x);
    }
    
    return n(x);
    
}

尾挪用优化

尾挪用特别的地方:与别的挪用差别的,在于它特别的挪用位置。

函数挪用会在内存构成一个“挪用纪录”,又称“挪用帧” (call frame),保留挪用位置和内部变量等信息。
假如在函数A的内部挪用函数B,那末在A的挪用帧上方,还会构成一个B的挪用帧。比及B运转完毕,将效果返回到A,B的挪用帧才会消逝。假如函数B内部还挪用函数C,那就另有一个C的挪用帧,以此推类。一切的挪用帧,就构成一个“挪用栈”(call stack)

尾挪用因为是函数的末了一步操纵,所以不须要保留外层函数的挪用帧,因为挪用位置,内部变量等信息都不会再运用到。只需直接用内层函数的挪用帧,庖代外层函数的挪用帧就可以够。

尾挪用优化:只保留内层函数的挪用帧

function fn () {
    let m = 1;
    let n = 2;
    return g(m+n); // 实行到这一步,完整可以删除fn()的挪用帧,只保留 g(3)  的挪用帧
}

fn();

// 同等于
function fn () {
    return g(3);
}

fn();

// 同等于
g(3);

// “尾挪用优化”: 只保留内层函数的挪用帧。

假如一切函数都是尾挪用,那末完整可以做到每次实行时,挪用帧只需一项,效果就大大节约内存。

注重:只需不再用到外层函数的内部变量,内层函数的挪用帧才会庖代外层函数的挪用帧,不然就没法举行“尾挪用优化”

尾递归

函数挪用本身,称为递归,假如尾挪用本身,就称之为:尾递归。

递归异常斲丧内存,因为须要同时保留成千上百个挪用帧,很轻易发作”栈溢出”毛病(stack voerflow).然则关于尾递归来讲,因为只存在一个挪用帧,所以不会发作”栈溢出”毛病。

// 对照阶乘  运用尾递归 和 不运用尾递归的情况

function factorial ( n ) {
    
    if ( n === 1 ) {
        return 1;
    }
    
    return n * factorial(n-1); 
    
}


// 尾递归
function factorial2 ( n, total ) {
    
    if ( n === 1 ) {
        return total;
    }
    
    return factorial2( n-1, n * total );
    
}

factorial2( 5, 1 ); // 120

递归函数的改写

尾递归的完成,每每须要改写递归函数,确保末了一步只挪用本身。做到这一点的要领,就是把一切用到的内部变量改写成函数的参数。

要领1:是在尾递归函数以外,再供应一个一般情势的函数。

function tailFactorial(n, total) {
  if (n === 1) return total;
  return tailFactorial(n - 1, n * total);
}

function factorial(n) {
  return tailFactorial(n, 1);
}

factorial(5) // 120

要领2:函数柯里化
柯里化:将多参数的函数转换成单参数的情势。(函数式编程的重要观点)

要领3:ES6的函数默许值

 function factorial ( n, total = 1 ) {
    
    if ( n === 1 ) return total;
    
    return factorial(n-1, n * total);
    
}

console.log( factorial(5) ); // 120;   

递归本质上是一种轮回操纵。地道的函数式编程言语没有轮回操纵敕令,一切的轮回都是运用递归完成。
关于支撑“尾挪用优化”的言语,只须要晓得轮回可以用递归替代。
假如一旦运用递归,就最好运用尾递归。

尾递归只在严厉情势下有效果

一般情势下:函数内部有两个变量,可以跟踪函数的挪用栈。

func.argumetns : 返回挪用时函数的参数
func.caller: 返回挪用当前函数的谁人函数。

尾递归优化见效的时刻,函数的挪用栈会改写,因而argumetns,caller会失真。严厉情势下禁用这两个变量。 所以尾递归情势仅在严厉情势下见效。

Set和Map数据组织

Set

基础用法

Set对象是ES6中新增的一种示意鸠合的数据组织。它相似于数组,然则成员的值都是唯一的。没有反复的值。

Set本身是一个组织函数,须要经由历程new关键字来天生。

Set函数可以接收一个数组(或相似数组的对象)作为参数,用来初始化。
取得的实例化对象是去反复的Set对象。

let s2 = new Set([123, 23, , 345, 345, 23]);

console.log(s2); // Set {123, 23, undefined, 345}
console.log(...s2); // 123 23 undefined 345

console.log( s2.size ); // 4

Set实例的属性和要领

Set组织的实例属性:

Set.prototype.constructor:组织函数,默许就是Set函数
Set.prototype.size: 返回Set实例的成员总数

Set实例要领分为:操纵要领(用于操纵数据) 和遍历要领(用于遍历成员)

操纵要领

  • add(value): 增加某个值,返回Set组织本身。
  • delete(value):删除某个值,返回一个布尔值,示意是不是删除胜利。
  • has(value):返回一个布尔值,示意该值是不是为Set成员。
  • cleart(): 消灭一切成员,没有返回值。

Array.form()可以将Set组织转为数组。

var items = new Set([1, 2, 3, 5, 6, 3, 4]);

console.log( Array.from(items) );  // [1, 2, 3, 5, 6, 4]

遍历操纵

  • keys(); 返回键名的迭代器。
  • values(); 返回键值的迭代器。
  • entries(); 返回键值对的迭代器。
  • forEach(); 运用回调函数遍历每一个成员。

Set组织的遍历递次是插进去递次。 运用场景比方:运用Set组织保留一个回调函数列表,挪用的时刻,就可以够保证根据增加递次挪用。

因为Set组织没有键名,只需键值(或许说键名和键值是同一个值)。 所以keys() 和values()是雷同的。

let set = new Set(['pink', 'cyan', 'tan']);

for (let item of set.keys()) {
  console.log(item);
}
// pink
// cyan
// tan

for (let item of set.values()) {
  console.log(item);
}
// pink
// cyan
// tan

for (let item of set.entries()) {
  console.log(item);
}
// ["pink", "pink"]
// ["cyan", "cyan"]
// ["tan", "tan"]        

Set组织的实例默许可遍历,它的默许遍历器天生函数就是它values要领。

console.log( Set.prototype[Symbol.iterator] === Set.prototype.values ); // true  

遍历的运用

  • 数组去重
  • 扩大运算符(...) 内部运用 for -of轮回
  • 完成交集,并集,差集。
  • 与Array.from()搭配运用
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}

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

WeakSet

WeakSet组织与Set组织相似,也是不反复的值的鸠合。

WeakSet是一个组织函数,须要经由历程new关键字。指定参数初始化。
参数:对象,或许 一个数组或相似数组的参数(具有Iterator接口的对象)

var ws = new WeakSet();

var a = [[1, 2], [3, 4]];

console.log( ws.add(a) ); // WeakSet {[Array[2], Array[2]]}
console.log( new WeakSet(a) );  // WeakSet {[1, 2], [3, 4]}


new WeakSet([1, 2]); // TypeError: Invalid value used in weak set
// 数组的成员成为WeakSet的成员,而不是数组本身,意味着,数组的成员只能是对象。

辨别:
1:WeakSet的成员只能是对象,而不能是别的范例的值。(具有Iterator接口的对象,都可以作为WeakSet参数)
2:WeakSet对象中弱援用,即渣滓接纳至机制不斟酌WeakSet对该对象的援用。也就是说:假如别的对象都不再援用该对象,那末渣滓接纳机制会自动接纳该对象所占的内存。(WeakSet存在内存中的新生代中,当Form空间和To空间的角色发作对调发觉没有援用就接纳),不斟酌对象还存在于WeakSet中。这个特征意味着,没法援用WeakSet成员,因而WeakSet是不可遍历。

var ws = new WeakSet();

console.log( ws.add(window) ); // window对象
console.log( ws.add({a: 10}) ); //  Object {a: 10}} 
// console.log( ws.add(Symbol()) );  // TypeError: Invalid value used in weak set
// console.log( ws.add(1) ); //  TypeError: Invalid value used in weak set
// console.log( ws.add('abc') ); //  TypeError: Invalid value used in weak set 

WeakSet组织要领

  • WeakSet.prototype.add(value): 向WeakSet实例增加一个新成员。
  • WeakSet.prototype.delete(value);:消灭WeakSet实例的指定成员
  • WeakSet.prototype.has(value);返回一个布尔值,示意某个值是不是在WeakSet实例当中。

    var ws = new WeakSet();

    ws.add(window);

    console.log( ws.has(window) ); // true

WeakSet组织的特征:

不能遍历,缘由:成员都是弱援用,随时都可以消逝。遍历机制没法保证成员的存在,极可以方才遍历组织,成员就取不到了。

典范的运用:
存储DOM节点,不必然则这些节点充文档移除时,会激发内存走漏。

Map

Map组织的目标和基础用法

JavaScript的对象,本质上是键值对的鸠合(Hash组织).然则传统上只能用字符串看成键

Map数据组织,相似对象,也是键值对的连系。然则“键”的局限不仅限于字符串。种种范例的值(包含对象)都可以看成键。
Object组织供应了一种“字符串-值”的对应。Map供应了一种“值-值”的对应。是一种更完美的Hash组织完成。


var m  = new Map();

var o = {p: 'hello'}

m.set(o, 'content');

console.log( m.get(o) ); // content

Map作为组织函数,参数可以是一个数组,该数组的成员是一个个示意键值对的数组。初始化函数。(注重是接收参数,二维数组)

var  m = new Map([['name', 'cyan']]);

console.log( m.get('name') );

假如对同一个键屡次赋值,背面的值将掩盖前面的值。
假如读取一个未知的键,返回undefined。

let colorsMap = new Map();

colorsMap.set(1, 'tan')
    .set(1, 'pink');
    
console.log( colorsMap.get(1) ); // pink    
new Map().get('asfddfsasadf'); // undefined

注重:只需同一个对象的援用 ,才是 同一个键。

let m = new Map();

m.set(['a'], 111);

console.log( m.get(['a']) ); // undefeinds
// 外表是同一个键,但现实上,这是两个值,内存地点是不一样的,因而get()要领没法读取该键,返回undefiend

Map的键,现实上是根内存地点绑定的,只需内存地点不一样,就视为两个键。 处理了:同名属性碰撞(clash) 题目。

假如Map的键是一个简朴范例的值(数字,字符串,布尔值), 则只需两个值严厉相称。Map将其视为一个键,包含(0,-0) 虽然NaN不严厉相称于本身,但Map将其视为同一个键

let map = new Map();

map.set(NaN, 123);
map.get(NaN) // 123

map.set(-0, 123);
map.get(+0) // 123

实例的属性和操纵要领

属性:
size属性
返回Map组织的成员总数

操纵要领:

  • set(key, value) :set()要领 设置key所对应的键值,返回正Map组织。假如key已有值,则键值会被更新,不然新天生该键 (set返回的是Map组织,可以运用链式写法)
  • get(key): get()要领读取key对应 键值,假如找不到key,返回undefined。
  • has(key): has();返回一个布尔值,示意某个键是不是在Map数据组织中。
  • delete(key): delete(); 删除某个键,返回布尔值,假如删除失利,返回false
  • clear(): 消灭一切成员,没有返回值。

遍历要领:

三个遍历器,一个遍历要领
Map的遍历递次就是插进去递次。

  • keys(): 返回键名的遍历器
  • values(): 返回键值的遍历器
  • entries(); 返回一切成员的遍历器
  • forEach(); 遍历Map的一切成员

let m = new Map([
    ['f', false],
    ['t', true]
]);


for ( let item of m.keys() ) {
    console.log( item );
}
// f
// t

for ( let item of m.values() ) {
    console.log( item );
}
// false
// true


for ( let item of m.entries() ) {
    console.log( item );
}
// ["f", false]
// ["t", true]

m.forEach( ( val, idx, map ) => {
    
    console.log( val, idx, map );
    
} );

Map与别的范例转换

Map转为数组

运用:扩大运算符...

let m = new Map([
    ['f', false],
    ['t', true]
]);

console.log(...m);  // ["f", false] ["t", true]

数组转为Map组织

把数组放入Map组织函数中,就可以够转为Map组织。

let m = new Map([
    ['f', false],
    ['t', true]
]);

Map组织转为对象

条件:一切Map组织中的键都是字符串,它可以转为对象

function strMapToObj ( strMap ) {
    let obj = Object.create(null);
    for ( let [k, v] of strMap ) {
        obj[k] = v;
    }
    return obj;
}
let myMap = new Map().set('yes', true).set('no', false);
console.log(strMapToObj(myMap) );  // Object {yes: true, no: false}

对象转为Map组织

function objtoStrMap ( obj ) {
    let strMap = new Map();
    for ( let k of Object.keys(obj) ) {
        strMap.set(k, obj[k]);
    }
    return strMap;
}

console.log( objtoStrMap({yes: true, no: false}) ); // Map {"yes" => true, "no" => false}

Map组织转为JSON

Map转为JSON分为两种:
Map的键名都是字符串,可以挑选JSON.stringify();
Map的键名有非字符串,可以挑选转为数组JSON

// Map 转为对象
function strMapToObj ( strMap ) {
    let obj = Object.create(null);
    for ( let [k, v] of strMap ) {
        obj[k] = v;
    }
    return obj;
}


// Map 转为JSON
function strMapToJson ( strMap ) {
    return JSON.stringify( strMapToObj(strMap) );
}

let myMap = new Map().set('yes', true).set('no', false);

console.log( strMapToJson(myMap) ); // {"yes":true,"no":false}


function mapToArrayJson ( map ) {
    return JSON.stringify([...map]);
}

let myMap2 = new Map().set('a', 'tan').set('b', 'pink').set('c', 'tan');

console.log( mapToArrayJson(myMap2) ); // [["a","tan"],["b","pink"],["c","tan"]] 
// 转为二维数组

JSON转为Map

JSON转为Map,一般状况下,一切键名都是字符串。

function objToStrMap ( obj ) {
    let strMap = new Map();
    for ( let k of Object.keys(obj) ) {
        strMap.set(k, obj[k]);
    }
    return strMap;
}

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

let json = '{"a": "tan", "b": "pink", "c": "cyan"}';

console.log( jsonToStrMap(json) ); // Map {"a" => "tan", "b" => "pink", "c" => "cyan"}


WeakMap

WakMap组织与Map组织基础相似。
辨别:只接收对象作为键名(null除外),不吸收别的范例的值作为键名,而且键名所指向的对象,不计入渣滓接纳机制。

WeakMap的设想目标在于,键名是对象的弱援用(渣滓接纳机制不应将援用斟酌在内),所以其对应的对象可以会被自动接纳。当对象被接纳后,WeakMap自动移除对应的键值对。
典范的: 一个对应的DOM元素的WeakMap组织,DOM节点作为键名。当某个DOM元素被消灭,其所对应的WeakMap纪录就会被自动被移出。基础上,WeakMap的运用场所,它的键所对应的对象,可以会在将来消逝。WeakMap组织有助于防备内存走漏

let wp = new WeakMap();

wp.set(document.body, 'body');

console.log( wp ); // WeakMap {body {} => "body"}

WeakMap的要领:

  • get()
  • set()
  • has()
  • delete()

Iterator和for-of轮回

Itertor(迭代器,遍历器)的观点

JavaScript原有的示意“鸠合”的数据组织,主如果数组和对象。ES6增加了Map,和Set。

需求:一种一致的接口机制,来处置惩罚一切差别的数据组织。

遍历器(Iterator),是一种接口,为个种种差别的数据组织供应一致的接见机制。
任何数据组织只需布置了Iterator接口,就可以够完成遍历操纵。(即顺次处置惩罚该数据接口的一切成员)

Iterator的作用:

  • 为种种数据组织,供应一个一致的,轻便的接见接口。
  • 使得数据组织的成员可以根据某种序次分列
  • ES6制造了一种新的遍历敕令for-of轮回,Iterator接口重要供for-of消耗

Iterator遍历历程:

  1. 建立一个指针对象,指向当亲啊数据组织的肇端位置。也就是说,遍历器对象本质上,就是一个指针对象。
  2. 第一次挪用指针对象的next()要领,可以将指针指向数据组织的第一个成员。
  3. 第二次挪用指针对象的next()要领,指针就指向数据组织的第二个成员。
  4. 不停挪用指针对象的next()要领,直到它指向数据组织的完毕位置。

每一次挪用next()要领,都邑返回数据组织的当前成员的信息。
详细:返回一个包含valuedone两个属性的对象。
value: 当前成员的值
done: 属性是一个布尔值,示意遍历是不是完毕。

let it = makeIterator(['a', 'b']);
    
    it.next();
    it.next();
    it.next();
    
    function makeIterator ( arr ) {
        
        var nextIndex = 0;
        return {
            next: function () {
                return nextIndex < array.length ? {  value: array[nextIdex++] } : { done: true }
            }
        }
        
    }
    // 定义一个函数,作用:遍历器对象。对数组['a', 'b'] 实行这个函数,就会返回该数组的遍历器对象(指针对象) it。

挪用的指针对象的next要领,就可以够遍历事前给定的数据组织。
因为Iterator只是把接口规格加到数据组织之上,遍历器与它所遍历的谁人数据组织,现实上是离开的,完整可以写出没有对应数据组织的遍历器对象,或许说用遍历器对象模仿出数据组织。

在ES6中,有些数据组织原生具有Iterator接口(比方数组),即不必任何处置惩罚,就可以够被for-of轮回遍历。有些数据组织就不可以直接被遍历(比方对象).
缘由:数据组织原生布置了Symbol.iterator属性。通常布置了Symbol.iterator属性的数据组织,就称为布置了遍历器接口,挪用这个接口,就会返回一个遍历器对象。

数据组织的默许Iterator接口

Iterator接口的目标:为一切的数据组织,供应一种一致的接见机制。
当运用for-of轮回遍历某种数据组织时,该轮回会自动寻觅Iterator接口。

ES6划定,默许的Iterator接口布置在数据组织的Symbol.iterator属性,或许说,一个数据组织只需具有Symbol.iterator属性,就可以够认为是“可遍历的”
挪用Symbol.iterator()要领,就会取得当前数据组织的默许的遍历器天生函数。Symbol.iterator本身是一个表达式,返回Symbl对象的iterator属性。 这是一个预定义好的,范例为Symbol的特别值,所以要放在方括号内。

ES6中三类数据组织原生具有Iterator接口:

  • 数组
  • 某些相似数组的对象
  • Set组织和Map组织

别的数据(主如果Object)的Iterator接口,须要本身的Symbol.iterator属性上面布置。
对象之所以没有默许布置Iterator接口,缘由:对象的谁人属性先遍历,谁人属性后遍历是不确定的。

本质上,遍历器是一种线性处置惩罚,关于任何非线性的数据组织,布置遍历器接口,就即是布置一种线性转换。

关于相似数组的对象(存在数值键名和length属性),布置Iterator接口,就是Symbol.iterator要领直接援用数组的Iterator接口。

NodeList.prototype[Symbol.iterator] = Array.prototype[Symbol.iterator];
// 或许
NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];

相似对数的对象挪用数组Symbl.iterator()

let iterable = {
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3,
    [Symbol.iterator]: Array.prototype[Symbol.iterator]
}

for ( let item of iterable ) {
    console.log(item);
}
// a
// b
// c

挪用Iterator接口的场所

默许挪用

解构赋值

对数组和Set组织举行解构赋值时,会默许挪用Symbol.iterator()要领

let s1 = new Set().add('a').add('b').add('c');

let [x ,y] = s1;

let [first, ...rest] = s1;

console.log( first, ...rest ); // a b c

扩大运算符

扩大运算符... 会默许挪用Iterator

let str = 'hello';

console.log( [...str] ); // ["h", "e", "l", "l", "o"]

let arr = ['b', 'c'];

console.log( ['a', ...arr, 'd'] ); // ["a", "b", "c", "d"] 

yield*

yield*背面跟的是一个可遍历的组织

别的场所

因为数组的遍历会挪用遍历器接口,所以任何接收数组作为参数的场所,实在都挪用了遍历器接口。

  • for…of
  • Array.from()
  • Map(), Set(), WeakMap(), WeakSet()(比方new Map([[‘a’,1],[‘b’,2]]))
  • Promise.all()
  • Promise.race()

字符串的Iterator接口

字符串是一个相似数组的对象,也原生具有Iterator接口。

let someString = 'hi';

console.log( typeof someString[Symbol.iterator] ); // function

let it = someString[Symbol.iterator](); // 指针对象

console.log( it.next() ); // Object {value: "h", done: false}
console.log( it.next() ); // Object {value: "i", done: false}
console.log( it.next() ); // Object {value: undefined, done: true}

for-of轮回

for-of轮回可以运用的局限包含数组,Set和Map组织,某些相似数组的对象(比方arguments对象,DOM NodeList对象),Generator对象,以及字符串。

JavaScript原有的for-in轮回,只能取得对象的键名,不能直接猎取键值,ES6供应的for-of轮回,许可遍历取得键值。

var arr = ['a', 'b', 'c', 'd'];

for ( let a in arr ) {
    console.log(a) // 0 1 2 3
}

for (let a of arr) {
    console.log( a ); // a b c d 
}

相似数组的对象都具有Iterator对象,经由历程Array.from();转为数组。

let arrayLike = { length: 2, 0: 'a', 1: 'b' };

// 报错
for (let x of arrayLike) {
  console.log(x);
}

// 准确
for (let x of Array.from(arrayLike)) {
  console.log(x);
}

别的遍历语法比较

最原始的运用for轮回。

瑕玷:写法贫苦

供应forEach();

瑕玷:没法半途跳出forEach轮回,break,return,continue不能见效。

for-in轮回

瑕玷:

  • 数组的键名是数字,然则for-in轮回是以字符串作为键名“0”,”1″,“2”等等。
  • for-in轮回不仅遍历数字键名,还会遍历手动增加的别的键,以至包含原型链上的键。
  • 某些状况下,for-in轮回会以恣意递次遍历键名。

for-in轮回主如果遍历对象,不实用遍历数组。

for-of轮回:

长处:

  • 有着同for-in一样的简介语法。
  • 差别于forEach(), 可以与break,continue和reutrn合营运用
  • 供应了遍历一切数据组织的一致操纵接口。

Promise对象

Promise是一种情势

Promise: 先知,(预先将你的将来示知,计划好你继承的路)
将异步操纵转换成更相符先知视角的情势展示

所谓Promise,简朴说就是一个容器,内里保留着某个将来才会完毕的事宜(通常是一个异步操纵)的效果。
语法上:Promise是一个对象,从它可以猎取异步操纵的音讯。Promise供应一致的API,种种异步操纵都可以用一样的要领举行处置惩罚。

Promise对象特征:

  • . 对象的状况不受外界影响。Promise对象代表一个异步操纵,有三种状况。

Pending(举行中),resolved(已完成,又称Fulfilled)rejected(已失利)

只需异步操纵的效果,可以决议当前是哪种状况,任何别的操纵都没法转变这个状况。示意无别的手腕转变。

  • . 一旦状况转变,就不会再变,任何时刻都可以取得这个效果。Promise 对象的状况转变。只需两种可以:Pending变成resolved 和 **从

Pending变成rejected** 任何一种都可以让状况凝结,就不会再继承变化。

Promise 瑕玷:

  • 没法作废Promise,一旦新建它就会马上实行,没法半途作废
  • 假如不设置回调函数,Promise内部抛出毛病,不会回响反映到外部。
  • 当处于Pending状况时,没法得知现在希望到哪个阶段(方才最先照样行将完成)

基础用法

var promise = new Promise(function ( resolve, reject ) {
    
    // some code

    if ( /* 异步操纵胜利 */ ) {
        resolve();
    } else {
        reject();
    }

});
    原文作者:alogy
    原文地址: https://segmentfault.com/a/1190000006120871
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞