ES6 笔记(未完)

一. let 和 const

1 let

基本用法

ES6新增let命令,与var用法类似,但所声明的变量只在声明的代码块中使用

{
    let a=10;
    var b=1;
}
a//a is not defined

b//1

var 声明的变量像是 static 的

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // a[1]->a[10]的值都是10
var a = [];
for (let i = 0; i < 10; i++) {//变量 i 使用 let 声明只在本轮循环有效,每次循环 值都是一个新的变量
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6
a[5]();//5

不存在变量提升

let 声明的变量一定要在声明后使用,否则报错

console.log(foo); // 输出undefined,foo 在此时已经存在
console.log(bar); // 报错ReferenceError

var foo = 2;
let bar = 2;

temporal dead zone

只要块级作用于存在letconst命令, 凡是在声明之前使用这些变量就会报错

var tmp = 123;

if (true) {
  tmp = 'abc'; // ReferenceError: tmp is not defined
  let tmp;
}

不允许重复声明

//let不允许在相同作用域内,重复声明同一个变量。

// 报错
function () {
  let a = 10;
  var a = 1;
}

// 报错
function () {
  let a = 10;
  let a = 1;
}
//因此,不能在函数内部重新声明参数。d[s

function func(arg) {
  let arg; // 报错
}

function func(arg) {
  {
    let arg; // 不报错
  }
}

2 块级作用域

为什么需要块级作用域?

第一种场景,内层变量可能会覆盖外层变量。

var tmp = new Date();

function f(){
  console.log(tmp);
  if (false){
    var tmp = "hello world";
  }
}

f() // undefined  内层的tmp变量覆盖了外层的tmp变量。

第二种场景,用来计数的循环变量泄露为全局变量。

var s = 'hello';

for (var i = 0; i < s.length; i++){
  console.log(s[i]);
}

console.log(i); // 5

ES6的块级作用域

let实际上为JavaScript新增了块级作用域。

function f1() {
  let n = 5;
  if (true) {
    let n = 10;
      console.log(n); // 10

  }
  console.log(n); // 5
}


{
  let a = 'secret';
  function f() {
    return a;
  }
}
f() // 报错
//上面代码中,块级作用域外部,无法调用块级作用域内部定义的函数。如果确实需要调用,就要像下面这样处理。

let f;
{
  let a = 'secret';
  f = function () {
    return a;
  }
}
f() // "secret"

3 const 命令

const 声明常量,类似于 java 中的 final,声明后无法修改其值

'use strict';
const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: "PI" is read-only

//常规模式下不会报错,但是修改无效
const PI = 3.1415;
PI = 3; // 常规模式时,重新赋值无效,但不报错
PI // 3.1415

const 声明的变量不得改变值, const 一旦声明变量则需要给其赋值,不能在后面赋值,这点与 java 不同.

'use strict';
const foo;
// SyntaxError: missing = in const declaration

const的作用域与let命令相同:只在声明所在的块级作用域内有效。

if (true) {
  const MAX = 5;
}

MAX // Uncaught ReferenceError: MAX is not defined

不可重复声明

var message = "Hello!";
let age = 25;

// 以下两行都会报错
const message = "Goodbye!";
const age = 30;

将对象声明为常量,特性与 java 一样

const foo = {};
foo.prop = 123;

foo.prop
// 123

foo = {} // TypeError: "foo" is read-only

const a = [];
a.push("Hello"); // 可执行
a.length = 0;    // 可执行
a = ["Dave"];    // 报错

如果想将对象冻结,使用Object.freeze方法

const foo = Object.freeze({});

// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

4 跨模块常量

// constants.js 模块
export const A = 1;
export const B = 3;
export const C = 4;

// test1.js 模块
import * as constants from './constants';
console.log(constants.A); // 1
console.log(constants.B); // 3

// test2.js 模块
import {A, B} from './constants';
console.log(A); // 1
console.log(B); // 3

5 全局对象属性

全局对象是最顶层的对象,在浏览器环境指的是window对象,在Node.js指的是global对象。ES5之中,全局对象的属性与全局变量是等价的。

二. 变量的解构赋值

ES6允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。

1 数组的解构赋值

//以前,为变量赋值,只能直接指定值。

var a = 1;
var b = 2;
var c = 3;

//ES6允许写成下面这样。
var [a, b, c] = [1, 2, 3];

只要等号两边的模式相同,左边的变量就会被赋予对应的值

let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3

let [ , , third] = ["foo", "bar", "baz"];
third // "baz"

let [x, , y] = [1, 2, 3];
x // 1
y // 3

let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]

let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []

不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组

let [x, y] = [1, 2, 3];
x // 1
y // 2

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

对于Set结构,也可以使用数组的解构赋值。

let [x, y, z] = new Set(["a", "b", "c"])
x // "a"

结构赋值允许指定默认值

var [foo = true] = [];
foo // true

[x, y = 'b'] = ['a'] // x='a', y='b'
[x, y = 'b'] = ['a', undefined] // x='a', y='b'

惰性赋值,在用到的时候才会求值

function f(){
  console.log('aaa');
}

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

//经过babel翻译后的代码

var _ = 1;
var x = _ === undefined ? f() : _;

默认值可以引用解构赋值的其他变量,但该变量必须已经声明。

let [x = 1, y = x] = [];     // x=1; y=1
let [x = 1, y = x] = [2];    // x=2; y=2
let [x = 1, y = x] = [1, 2]; // x=1; y=2
let [x = y, y = 1] = [];     // ReferenceError

2. 对象的解构赋值(重要!!)

与数组不同的是,对象属性没有次序,变量必须与属性同名才能取到正确值


var { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"

///相对应下面代码

var _foo$bar = { foo: "aaa", bar: "bbb" };
var bar = _foo$bar.bar;
var foo = _foo$bar.foo;


var { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined

let { log, sin, cos } = Math;
/////////
var log = Math.log;
var sin = Math.sin;
var cos = Math.cos;

变量可以重命名


var { foo: baz } = { foo: "aaa", bar: "bbb" };
baz // "aaa"
////
var _foo$bar = { foo: "aaa", bar: "bbb" };
var baz = _foo$bar.foo;


let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj;
f // 'hello'
l // 'world'
//////////
var obj = { first: 'hello', last: 'world' };
var f = obj.first;
var l = obj.last;

3. 函数参数的解构赋值


function move({x = 0, y = 0} = {}) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, 0]
move({}); // [0, 0]
move(); // [0, 0]


////--转义后--

function move() {
  var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];

  var _ref$x = _ref.x;
  var x = _ref$x === undefined ? 0 : _ref$x;
  var _ref$y = _ref.y;
  var y = _ref$y === undefined ? 0 : _ref$y;

  return [x, y];
}

另一种写法

function move({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}

move({x: 3, y: 8}); // [3, 8]
move({x: 3}); // [3, undefined]
move({}); // [undefined, undefined]
move(); // [0, 0]
////////
function move() {
  var _ref = arguments.length <= 0 || arguments[0] === undefined ? { x: 0, y: 0 } : arguments[0];

  var x = _ref.x;
  var y = _ref.y;

  return [x, y];
}

6.其他解构

字符串解构

const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"

let {length : len} = 'hello';
len // 5

数值解构

let {toString: s} = 123;
//////

var _ = 123;
var s = _.toString;

7 用途

交换变量值

[x, y] = [y, x];
/////
var _ref2 = [y, x];
x = _ref2[0];
y = _ref2[1];

函数返回多个值

// 返回一个数组

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数据

var jsonData = {
  id: 42,
  status: "OK",
  data: [867, 5309]
}

let { id, status, data: number } = jsonData;

console.log(id, status, number)
// 42, "OK", [867, 5309]

//////
var id = jsonData.id;
var status = jsonData.status;
var number = jsonData.data;

遍历MAP结构


var map = new Map();
map.set('first', 'hello');
map.set('second', 'world');

for (let [key, value] of map) {
  console.log(key + " is " + value);
}
// first is hello
// second is world

模块导入

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

三. 类型

ECMAScript 有 5 种原始类型,即 Undefined、Null、Boolean、Number 和 String。

1. Undefined

如前所述,Undefined 类型只有一个值,即 undefined。当声明的变量未初始化时,该变量的默认值是undefined

2. Null

Null 类型只有一个值null ,值 undefined 实际上是从值 null 派生来的

null == undefined;//true
null === undefined;//false

3. Number

八进制数和十六进制数,ES5 之后八进制用0o表示

var iNum = 0o70;  //070 等于十进制的 56
var iNum = 0x1f;  //0x1f 等于十进制的 31

如果要将0b和0x前缀的字符串数值转为十进制,要使用Number方法。

Number('0b111')  // 7
Number('0o10')  // 8

4. String

5. 类型转换

转换成字符串 toString() 方法

arrayObject.toString()
booleanObject.toString()
dateObject.toString()
NumberObject.toString()
stringObject.toString()

转换成数字parseInt() 、 parseFloat()


var iNum1 = parseInt("12345red");   //返回 12345
var iNum1 = parseInt("0xA");    //返回 10
var iNum1 = parseInt("56.9");   //返回 56
var iNum1 = parseInt("red");    //返回 NaN

var fNum1 = parseFloat("12345red"); //返回 12345
var fNum2 = parseFloat("0xA");  //返回 NaN
var fNum3 = parseFloat("11.2"); //返回 11.2
var fNum4 = parseFloat("11.22.33"); //返回 11.22
var fNum5 = parseFloat("0102"); //返回 102
var fNum1 = parseFloat("red");  //返回 NaN

6.强制类型转换

ECMAScript 中可用的 3 种强制类型转换如下:

  • Boolean(value) - 把给定的值转换成 Boolean 型;
  • Number(value) - 把给定的值转换成数字(可以是整数或浮点数);
  • String(value) - 把给定的值转换成字符串;

四. 数组

1. Array.from()

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括ES6新增的数据结构Set和Map)所谓类似数组的对象,本质特征只有一点,即必须有length属性,因此,任何有length属性的对象,都可以通过Array.from方法转为数组。

Array.from('hello')
// ['h', 'e', 'l', 'l', 'o']

let namesSet = new Set(['a', 'b'])
Array.from(namesSet) // ['a', 'b']


...运算符也可以将某些结构转换成数组

function foo() {
  var args = [...arguments];
}
////////

function foo() {
    var args = [].concat(_slice.call(arguments));
}


var t=[..."helloworld"] //["h","e","l","l","o","w","o","r","l","d"]

Array.from还可以接受第二个参数,用来对每个元素进行处理,将处理后的值放入返回的数组。

Array.from(arrayLike, x => x * x);
///////
Array.from(arrayLike, function (x) {
    return x * x;
});


Array.from([1, 2, 3], (x) => x * x)// [1, 4, 9]

////////
Array.from([1, 2, 3], function (x) {
    return x * x;
});

2. Array.of()

Array.of方法用于将一组值,转换为数组。


Array.of(3, 11, 8) // [3,11,8]
Array.of(3) // [3]
Array.of(3).length // 1

//Array.of方法可以用下面的代码模拟实现。

function ArrayOf(){
  return [].slice.call(arguments);
}

3. find() findIndex()

find方法用于找出第一个符合条件的数组成员,参数是一个回调函数

[1, 4, -5, 10].find((n) => n < 0)//-5
/////

[1, 4, -5, 10].find(function (n) {
 return n < 0;
});


[1, 5, 10, 15].find(function(value, index, arr) {//依次为当前的值、当前的位置和原数组。
 return value > 9;
}) // 10

findIndex方法用于返回符合条件值的位置,如果没有符合的返回-1


[1, 5, 10, 15].findIndex(function(value, index, arr) {
  return value > 9;
}) // 2

5. fill()

填充数组

['a', 'b', 'c'].fill(7)
// [7, 7, 7]

new Array(3).fill(7)
// [7, 7, 7]

6. includes()

用来检测数组里是否包含某个值

[1, 2, 3].includes(2);     // true
[1, 2, 3].includes(4);     // false
[1, 2, NaN].includes(NaN); // true

7. 数组推导

使用现有数组生成新数组


var a1 = [1, 2, 3, 4];
var a2 = [for (i of a1) i * 2];

a2 // [2, 4, 6, 8]
 
var years = [ 1954, 1974, 1990, 2006, 2010, 2014 ];

[for (year of years) if (year > 2000) year];
// [ 2006, 2010, 2014 ]

[for (year of years) if (year > 2000) if(year < 2010) year];
// [ 2006]

[for (year of years) if (year > 2000 && year < 2010) year];
// [ 2006]


[for (i of [1, 2, 3]) i * i];
// 等价于
[1, 2, 3].map(function (i) { return i * i });

[for (i of [1,4,2,3,-8]) if (i < 3) i];
// 等价于
[1,4,2,3,-8].filter(function(i) { return i < 3 });

五. 函数

1. 参数默认值

ES6可以为函数参数设置默认值

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

log('Hello') // Hello World
log('Hello', 'China') // Hello China
log('Hello', '') // Hello


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

var p = new Point();
p // { x: 0, y: 0 }

可以结合解构赋值使用


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

foo({}) // undefined, 5
foo({x: 1}) // 1, 5
foo({x: 1, y: 2}) // 1, 2
foo() // TypeError: Cannot read property 'x' of undefined

function fetch(url, { body = '', method = 'GET', headers = {} }){
  console.log(method);
}

fetch('http://example.com', {})
// "GET"

fetch('http://example.com')
// 报错

上面这种写法不能省略第二个参数,如果给第二个参数默认值则可以省略

function fetch(url, { method = 'GET' } = {}){
  console.log(method);
}

fetch('http://example.com')
// "GET"

需注意的情况

// 写法一
function m1({x = 0, y = 0} = {}) {
  return [x, y];
}

// 写法二
function m2({x, y} = { x: 0, y: 0 }) {
  return [x, y];
}




// 函数没有参数的情况
m1() // [0, 0]
m2() // [0, 0]

// x和y都有值的情况
m1({x: 3, y: 8}) // [3, 8]
m2({x: 3, y: 8}) // [3, 8]

// x有值,y无值的情况
m1({x: 3}) // [3, 0]
m2({x: 3}) // [3, undefined]

// x和y都无值的情况
m1({}) // [0, 0];
m2({}) // [undefined, undefined]

m1({z: 3}) // [0, 0]
m2({z: 3}) // [undefined, undefined]


参数默认值的位置

非尾部参数设置默认值,这个参数是无法省略的

function f(x = 1, y) {
  return [x, y];
}
///////
function f(x, y) {
  if (x === undefined) x = 1;

  return [x, y];
}


f() // [1, undefined]
f(2) // [2, undefined])
f(, 1) // 报错,其实本身这种语法就是错误的
f(undefined, 1) // [1, 1]

function f(x, y = 5, z) {
  return [x, y, z];
}

f() // [undefined, 5, undefined]
f(1) // [1, 5, undefined]
f(1, ,2) // 报错
f(1, undefined, 2) // [1, 5, 2]

函数的length属性

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数

(function(a){}).length // 1
(function(a = 5){}).length // 0
(function(a, b, c = 5){}).length // 2

默认值参数作用域

总结起来就是参数使用的变量已经生成则作用域是函数作用域否则更上层的作用域的变量已经生成则使用的是上层作用域的值,如果全局内都没有此变量存在则会报错

情况1:

var x = 1;

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

f(2) // 2

情况2:

let x = 1;

function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // 1

情况3:


function f(y = x) {
  let x = 2;
  console.log(y);
}

f() // ReferenceError: x is not defined

2. rest参数

就是...变量名形式的参数,表示不定数量的参数

function add(...values) {
  let sum = 0;

  for (var val of values) {
    sum += val;
  }

  return sum;
}

add(2, 5, 3) // 10

rest参数后不能再有其他参数


// 报错
function f(a, ...b, c) {
  // ...
}

注意函数的length属性不包括rest参数

(function(a) {}).length  // 1
(function(...a) {}).length  // 0
(function(a, ...b) {}).length  // 1

3. 扩展运算符(spread)

扩展运算符用...表示,用于将一个数组转换为逗号分隔的参数序列。

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

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

主要用于函数调用

//多么扭曲的例子=_=
function f(v, w, x, y, z) { }
var args = [0, 1];
f(-1, ...args, 2, ...[3]);

替代apply方法

// ES5的写法
function f(x, y, z) {
  // ...
}
var args = [0, 1, 2];
f.apply(null, args);

// ES6的写法
function f(x, y, z) {
  // ...
}
var args = [0, 1, 2];
f(...args);

// ES5的写法
Math.max.apply(null, [14, 3, 77])

// ES6的写法
Math.max(...[14, 3, 77])

// 等同于
Math.max(14, 3, 77);

合并数组

// ES5
[1, 2].concat(more)
// ES6
[1, 2, ...more]

var arr1 = ['a', 'b'];
var arr2 = ['c'];
var arr3 = ['d', 'e'];

// ES5的合并数组
arr1.concat(arr2, arr3));
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

扩展解构赋值

const [first, ...rest] = [1, 2, 3, 4, 5];
first // 1
rest  // [2, 3, 4, 5]

const [first, ...rest] = [];
first // undefined
rest  // []:

const [first, ...rest] = ["foo"];
first  // "foo"
rest   // []

需要注意的是将扩展运算符用于数组赋值则只能放在参数最后一位,否则会报错


const [...butLast, last] = [1, 2, 3, 4, 5];
// 报错

const [first, ...middle, last] = [1, 2, 3, 4, 5];
// 报错

map set结构

let map = new Map([
  [1, 'one'],
  [2, 'two'],
  [3, 'three'],
]);

let arr = [...map.keys()]; // [1, 2, 3]

4. name属性

用于返回该函数的函数名

var func1 = function () {};

// ES5
func1.name // ""

// ES6
func1.name // "func1"

5.箭头函数

es6可以使用=>定义函数, => 左边代表参数名

var f=v=>v;

///等价于///

var f = function(v) {
  return v;
};

如果箭头函数不需要参数或者需要多个参数,使用括号代表参数部分

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

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

如果方法体多于一行,则需要用{}并使用return 返回

var sum = (num1, num2) => { return num1 + num2; }

///////
var sum = function sum(num1, num2) {
  return num1 + num2;
};

如果箭头部分直接返回对象,则必须在对象外边加上括号

var getTempItem = id => ({id:id,name:"Temp"});
///////
var getTempItem = function getTempItem(id) {
  return { id: id, name: "Temp" };
};

6. 函数绑定

函数绑定运算符是::,双冒号左边是对象,右边是一个函数,运算符会自动将左边的对象作为上下文环境,绑定到右边的函数上


foo::bar;
// 等同于
bar.bind(foo);

foo::bar(...arguments);
// 等同于
bar.apply(foo, arguments);

const hasOwnProperty = Object.prototype.hasOwnProperty;
function hasOwn(obj, key) {
  return obj::hasOwnProperty(key);
}

如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面。

var method = obj::obj.foo;
// 等同于
var method = ::obj.foo;

let log = ::console.log;
// 等同于
var log = console.log.bind(console);

7. 尾调用优化

尾调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是调用另一个函数。

function f(x){
  return g(x);
}

尾调用优化即只保留内层函数的调用帧.

如下例子,g函数调用后f就结束,则在最后执行g的时候f可以不用保留

function f() {
  let m = 1;
  let n = 2;
  return g(m + n);
}
f();

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

// 等同于
g(3);

尾递归

通过尾调用优化可以节省尾递归产生的栈内存


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

factorial(5, 1) // 120

尾调用优化只在严格模式下开启

六. 对象

七. Proxy和Reflect

八. Set和Map数据结构

1. Set

初始化

var s = new Set();

var set = new Set([1, 2, 3, 4, 4])



添加数据

var s = new Set();

s.add(1);

两个对象总是不相等的。

let set = new Set();

set.add({})
set.size // 1

set.add({})
set.size // 2

操作方法:

  • add(value):添加某个值,返回Set结构本身。
  • delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
  • has(value):返回一个布尔值,表示该值是否为Set的成员。
  • clear():清除所有成员,没有返回值。

s.add(1).add(2).add(2);
// 注意2被加入了两次

s.size // 2

s.has(1) // true
s.has(2) // true
s.has(3) // false

s.delete(2);
s.has(2) // false

遍历操作:

  • keys():返回一个键名的遍历器
  • values():返回一个键值的遍历器
  • entries():返回一个键值对的遍历器
  • forEach():使用回调函数遍历每个成员
let set = new Set(['red', 'green', 'blue']);

for ( let item of set.keys() ){
  console.log(item);
}
// red
// green
// blue

for ( let item of set.values() ){
  console.log(item);
}
// red
// green
// blue

for ( let item of set.entries() ){
  console.log(item);
}
// ["red", "red"]
// ["green", "green"]
// ["blue", "blue"]

2. Map

初始化


var m = new Map();
var o = {p: "Hello World"};

m.set(o, "content")
m.get(o) // "content"

m.has(o) // true
m.delete(o) // true
m.has(o) // false


var map = new Map([["name", "张三"], ["title", "Author"]]);

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

操作方法

  • size属性: 返回Map成员总数
  • set(key, value):设置key所对应的键值
  • get(key):读取key对应的键值如果找不到key,返回undefined
  • has(key):返回一个布尔值,表示某个键是否在Map数据结构中
  • delete(key):删除某个键,返回true。如果删除失败,返回false
  • clear():方法清除所有成员,没有返回值

遍历方法

  • keys():返回键名的遍历器。
  • values():返回键值的遍历器。
  • entries():返回所有成员的遍历器。
  • forEach():遍历Map的所有成员。
let map = new Map([
  ['F', 'no'],
  ['T',  'yes'],
]);

for (let key of map.keys()) {
  console.log(key);
}
// "F"
// "T"

for (let value of map.values()) {
  console.log(value);
}
// "no"
// "yes"

for (let item of map.entries()) {
  console.log(item[0], item[1]);
}
// "F" "no"
// "T" "yes"

// 或者
for (let [key, value] of map.entries()) {
  console.log(key, value);
}

// 等同于使用map.entries()
for (let [key, value] of map) {
  console.log(key, value);
}

与其他结构互转(TODO:)

九. Class

十. 异步

JS 是单线程模型的,在浏览器环境下 JS和其他浏览器任务共享同一个线程,在一个任务执行过程中会阻塞其他任务.

我们不能阻塞主线程太长时间,异步就是用来解决这种情况的.

常见的异步编程有以下四种:

  • 回调函数
  • 事件监听
  • 发布/订阅
  • Promise 对象

1. 回调函数

2. 事件监听

在浏览器下的 js 编程中我们经常会写到这样的事件监听代码


var image1=document.querySelector('.img-1');

image1.addEventListener('load',()={
//图片加载完成
});

image1.addEventListener('error',()=>{
//出现错误
})

3. 发布/订阅

4. Promise(重要!!)

Promise 是异步编程的一种解决方案

4.1 基本用法

生成 Promise 实例

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

  if (/* 异步操作成功 */){
    resolve(value);
  } else {
    reject(error);
  }
});

Promise 构造函数接受一个函数作为参数,该函数有两个参数resolvereject.这两个函数由 JS 引擎提供不用自己部署.

resolve函数作用是将 Promise 对象的状态从未完成(Pending)变成成功(Reolved)在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态未完变为失败,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定Resolved状态和Reject状态的回调函数。

promise.then(function(value) {
  // success
}, function(value) {
  // failure
});
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,780评论 4 369
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,424评论 1 305
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,397评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,576评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,997评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,945评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,107评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,850评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,625评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,804评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,285评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,613评论 3 261
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,291评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,164评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,963评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,096评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,886评论 2 278

推荐阅读更多精彩内容

  • 官方中文版原文链接 感谢社区中各位的大力支持,译者再次奉上一点点福利:阿里云产品券,享受所有官网优惠,并抽取幸运大...
    HetfieldJoe阅读 2,999评论 3 37
  • 《ECMAScript6 入门》阮一峰 读书笔记 let和constlet声明的变量仅在块级作用域内有效,var声...
    亲爱的孟良阅读 662评论 1 2
  • 三,字符串扩展 3.1 Unicode表示法 ES6 做出了改进,只要将码点放入大括号,就能正确解读该字符。有了这...
    eastbaby阅读 1,444评论 0 8
  • 1 认识他是在微博 ,因为那时候是高二升高三的那个暑假,所以每天没事就会刷刷微博,看看学习方法。因为学习,就认识他...
    默默的小狮子阅读 525评论 0 2
  • 昨天晚上,有一位共事的伙伴要走了,走之前要去吃顿“散伙饭”。通常这样的聚餐,我心里是五味杂陈,去与不去心里都难受。...
    九月雏菊阅读 752评论 0 16