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 聲明只在本輪循環(huán)有效,每次循環(huán) 值都是一個新的變量
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6
a[5]();//5

不存在變量提升

let 聲明的變量一定要在聲明后使用,否則報錯

console.log(foo); // 輸出undefined,foo 在此時已經(jīng)存在
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;
}

不允許重復(fù)聲明

//let不允許在相同作用域內(nèi),重復(fù)聲明同一個變量庶喜。

// 報錯
function () {
  let a = 10;
  var a = 1;
}

// 報錯
function () {
  let a = 10;
  let a = 1;
}
//因此,不能在函數(shù)內(nèi)部重新聲明參數(shù)救鲤。d[s

function func(arg) {
  let arg; // 報錯
}

function func(arg) {
  {
    let arg; // 不報錯
  }
}

2 塊級作用域

為什么需要塊級作用域久窟?

第一種場景,內(nèi)層變量可能會覆蓋外層變量本缠。

var tmp = new Date();

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

f() // undefined  內(nèi)層的tmp變量覆蓋了外層的tmp變量斥扛。

第二種場景,用來計數(shù)的循環(huán)變量泄露為全局變量丹锹。

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() // 報錯
//上面代碼中,塊級作用域外部楣黍,無法調(diào)用塊級作用域內(nèi)部定義的函數(shù)峻村。如果確實需要調(diào)用,就要像下面這樣處理锡凝。

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

//常規(guī)模式下不會報錯,但是修改無效
const PI = 3.1415;
PI = 3; // 常規(guī)模式時,重新賦值無效垢啼,但不報錯
PI // 3.1415

const 聲明的變量不得改變值, const 一旦聲明變量則需要給其賦值,不能在后面賦值,這點與 java 不同.

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

const的作用域與let命令相同:只在聲明所在的塊級作用域內(nèi)有效窜锯。

if (true) {
  const MAX = 5;
}

MAX // Uncaught ReferenceError: MAX is not defined

不可重復(fù)聲明

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"); // 可執(zhí)行
a.length = 0;    // 可執(zhí)行
a = ["Dave"];    // 報錯

如果想將對象凍結(jié),使用Object.freeze方法

const foo = Object.freeze({});

// 常規(guī)模式時,下面一行不起作用芭析;
// 嚴格模式時锚扎,該行會報錯
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 全局對象屬性

全局對象是最頂層的對象,在瀏覽器環(huán)境指的是window對象馁启,在Node.js指的是global對象驾孔。ES5之中芍秆,全局對象的屬性與全局變量是等價的。

二. 變量的解構(gòu)賦值

ES6允許按照一定模式翠勉,從數(shù)組和對象中提取值妖啥,對變量進行賦值,這被稱為解構(gòu)(Destructuring)对碌。

1 數(shù)組的解構(gòu)賦值

//以前荆虱,為變量賦值,只能直接指定值朽们。

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

//ES6允許寫成下面這樣怀读。
var [a, b, c] = [1, 2, 3];

只要等號兩邊的模式相同,左邊的變量就會被賦予對應(yīng)的值

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 // []

不完全解構(gòu)骑脱,即等號左邊的模式菜枷,只匹配一部分的等號右邊的數(shù)組

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結(jié)構(gòu),也可以使用數(shù)組的解構(gòu)賦值叁丧。

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

結(jié)構(gòu)賦值允許指定默認值

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];

//經(jīng)過babel翻譯后的代碼

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

默認值可以引用解構(gòu)賦值的其他變量,但該變量必須已經(jīng)聲明歹袁。

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. 對象的解構(gòu)賦值(重要?姥堋!)

與數(shù)組不同的是条舔,對象屬性沒有次序枫耳,變量必須與屬性同名才能取到正確值


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

///相對應(yīng)下面代碼

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. 函數(shù)參數(shù)的解構(gòu)賦值


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]


////--轉(zhuǎn)義后--

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.其他解構(gòu)

字符串解構(gòu)

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

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

數(shù)值解構(gòu)

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

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

7 用途

交換變量值

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

函數(shù)返回多個值

// 返回一個數(shù)組

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

// 返回一個對象

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

函數(shù)參數(shù)定義


// 參數(shù)是一組有次序的值
function f([x, y, z]) { ... }
f([1, 2, 3])

// 參數(shù)是一組無次序的值
function f({x, y, z}) { ... }
f({z: 3, y: 2, x: 1})

提取Json數(shù)據(jù)

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結(jié)構(gòu)


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

模塊導(dǎo)入

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

八進制數(shù)和十六進制數(shù),ES5 之后八進制用0o表示

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

如果要將0b和0x前綴的字符串數(shù)值轉(zhuǎn)為十進制骏全,要使用Number方法。

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

4. String

5. 類型轉(zhuǎn)換

轉(zhuǎn)換成字符串 toString() 方法

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

轉(zhuǎn)換成數(shù)字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.強制類型轉(zhuǎn)換

ECMAScript 中可用的 3 種強制類型轉(zhuǎn)換如下:

  • Boolean(value) - 把給定的值轉(zhuǎn)換成 Boolean 型姜贡;
  • Number(value) - 把給定的值轉(zhuǎn)換成數(shù)字(可以是整數(shù)或浮點數(shù));
  • String(value) - 把給定的值轉(zhuǎn)換成字符串棺棵;

四. 數(shù)組

1. Array.from()

Array.from方法用于將兩類對象轉(zhuǎn)為真正的數(shù)組:類似數(shù)組的對象(array-like object)和可遍歷(iterable)的對象(包括ES6新增的數(shù)據(jù)結(jié)構(gòu)Set和Map)所謂類似數(shù)組的對象楼咳,本質(zhì)特征只有一點熄捍,即必須有l(wèi)ength屬性,因此,任何有l(wèi)ength屬性的對象母怜,都可以通過Array.from方法轉(zhuǎn)為數(shù)組余耽。

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

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


...運算符也可以將某些結(jié)構(gòu)轉(zhuǎn)換成數(shù)組

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還可以接受第二個參數(shù),用來對每個元素進行處理糙申,將處理后的值放入返回的數(shù)組宾添。

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方法用于將一組值,轉(zhuǎn)換為數(shù)組柜裸。


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

//Array.of方法可以用下面的代碼模擬實現(xiàn)缕陕。

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

3. find() findIndex()

find方法用于找出第一個符合條件的數(shù)組成員,參數(shù)是一個回調(diào)函數(shù)

[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) {//依次為當前的值疙挺、當前的位置和原數(shù)組扛邑。
 return value > 9;
}) // 10

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


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

5. fill()

填充數(shù)組

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

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

6. includes()

用來檢測數(shù)組里是否包含某個值

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

7. 數(shù)組推導(dǎo)

使用現(xiàn)有數(shù)組生成新數(shù)組


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 });

五. 函數(shù)

1. 參數(shù)默認值

ES6可以為函數(shù)參數(shù)設(shè)置默認值

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 }

可以結(jié)合解構(gòu)賦值使用


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')
// 報錯

上面這種寫法不能省略第二個參數(shù)铐然,如果給第二個參數(shù)默認值則可以省略

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];
}




// 函數(shù)沒有參數(shù)的情況
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]


參數(shù)默認值的位置

非尾部參數(shù)設(shè)置默認值,這個參數(shù)是無法省略的

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]

函數(shù)的length屬性

指定了默認值以后搀暑,函數(shù)的length屬性沥阳,將返回沒有指定默認值的參數(shù)個數(shù)

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

默認值參數(shù)作用域

總結(jié)起來就是參數(shù)使用的變量已經(jīng)生成則作用域是函數(shù)作用域否則更上層的作用域的變量已經(jīng)生成則使用的是上層作用域的值,如果全局內(nèi)都沒有此變量存在則會報錯

情況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參數(shù)

就是...變量名形式的參數(shù),表示不定數(shù)量的參數(shù)

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

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

  return sum;
}

add(2, 5, 3) // 10

rest參數(shù)后不能再有其他參數(shù)


// 報錯
function f(a, ...b, c) {
  // ...
}

注意函數(shù)的length屬性不包括rest參數(shù)

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

3. 擴展運算符(spread)

擴展運算符用...表示,用于將一個數(shù)組轉(zhuǎn)換為逗號分隔的參數(shù)序列朽砰。

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

主要用于函數(shù)調(diào)用

//多么扭曲的例子=_=
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);

合并數(shù)組

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

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

// ES5的合并數(shù)組
arr1.concat(arr2, arr3));
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6的合并數(shù)組
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]

擴展解構(gòu)賦值

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   // []

需要注意的是將擴展運算符用于數(shù)組賦值則只能放在參數(shù)最后一位潮峦,否則會報錯


const [...butLast, last] = [1, 2, 3, 4, 5];
// 報錯

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

map set結(jié)構(gòu)

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

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

4. name屬性

用于返回該函數(shù)的函數(shù)名

var func1 = function () {};

// ES5
func1.name // ""

// ES6
func1.name // "func1"

5.箭頭函數(shù)

es6可以使用=>定義函數(shù), => 左邊代表參數(shù)名

var f=v=>v;

///等價于///

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

如果箭頭函數(shù)不需要參數(shù)或者需要多個參數(shù),使用括號代表參數(shù)部分

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. 函數(shù)綁定

函數(shù)綁定運算符是::,雙冒號左邊是對象,右邊是一個函數(shù),運算符會自動將左邊的對象作為上下文環(huán)境,綁定到右邊的函數(shù)上


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. 尾調(diào)用優(yōu)化

尾調(diào)用(Tail Call)是函數(shù)式編程的一個重要概念,就是指某個函數(shù)的最后一步是調(diào)用另一個函數(shù)。

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

尾調(diào)用優(yōu)化即只保留內(nèi)層函數(shù)的調(diào)用幀.

如下例子,g函數(shù)調(diào)用后f就結(jié)束,則在最后執(zhí)行g(shù)的時候f可以不用保留

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

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

// 等同于
g(3);

尾遞歸

通過尾調(diào)用優(yōu)化可以節(jié)省尾遞歸產(chǎn)生的棧內(nèi)存


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

factorial(5, 1) // 120

尾調(diào)用優(yōu)化只在嚴格模式下開啟

六. 對象

七. Proxy和Reflect

八. Set和Map數(shù)據(jù)結(jié)構(gòu)

1. Set

初始化

var s = new Set();

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



添加數(shù)據(jù)

var s = new Set();

s.add(1);

兩個對象總是不相等的薪伏。

let set = new Set();

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

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

操作方法:

  • add(value):添加某個值,返回Set結(jié)構(gòu)本身粗仓。
  • 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():使用回調(diào)函數(shù)遍歷每個成員
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成員總數(shù)
  • set(key, value):設(shè)置key所對應(yīng)的鍵值
  • get(key):讀取key對應(yīng)的鍵值如果找不到key即寒,返回undefined
  • has(key):返回一個布爾值橡淆,表示某個鍵是否在Map數(shù)據(jù)結(jié)構(gòu)中
  • 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);
}

與其他結(jié)構(gòu)互轉(zhuǎn)(TODO:)

九. Class

十. 異步

JS 是單線程模型的,在瀏覽器環(huán)境下 JS和其他瀏覽器任務(wù)共享同一個線程,在一個任務(wù)執(zhí)行過程中會阻塞其他任務(wù).

我們不能阻塞主線程太長時間,異步就是用來解決這種情況的.

常見的異步編程有以下四種:

  • 回調(diào)函數(shù)
  • 事件監(jiān)聽
  • 發(fā)布/訂閱
  • Promise 對象

1. 回調(diào)函數(shù)

2. 事件監(jiān)聽

在瀏覽器下的 js 編程中我們經(jīng)常會寫到這樣的事件監(jiān)聽代碼


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

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

image1.addEventListener('error',()=>{
//出現(xiàn)錯誤
})

3. 發(fā)布/訂閱

4. Promise(重要!!)

Promise 是異步編程的一種解決方案

4.1 基本用法

生成 Promise 實例

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

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

Promise 構(gòu)造函數(shù)接受一個函數(shù)作為參數(shù),該函數(shù)有兩個參數(shù)resolvereject.這兩個函數(shù)由 JS 引擎提供不用自己部署.

resolve函數(shù)作用是將 Promise 對象的狀態(tài)從未完成(Pending)變成成功(Reolved)在異步操作成功時調(diào)用趋艘,并將異步操作的結(jié)果疲恢,作為參數(shù)傳遞出去;reject函數(shù)的作用是瓷胧,將Promise對象的狀態(tài)未完變?yōu)?strong>失敗显拳,在異步操作失敗時調(diào)用,并將異步操作報出的錯誤搓萧,作為參數(shù)傳遞出去杂数。

Promise實例生成以后,可以用then方法分別指定Resolved狀態(tài)和Reject狀態(tài)的回調(diào)函數(shù)瘸洛。

promise.then(function(value) {
  // success
}, function(value) {
  // failure
});
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末揍移,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子反肋,更是在濱河造成了極大的恐慌那伐,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,194評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件囚玫,死亡現(xiàn)場離奇詭異喧锦,居然都是意外死亡,警方通過查閱死者的電腦和手機抓督,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評論 2 385
  • 文/潘曉璐 我一進店門燃少,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人铃在,你說我怎么就攤上這事阵具。” “怎么了定铜?”我有些...
    開封第一講書人閱讀 156,780評論 0 346
  • 文/不壞的土叔 我叫張陵阳液,是天一觀的道長。 經(jīng)常有香客問我揣炕,道長帘皿,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,388評論 1 283
  • 正文 為了忘掉前任畸陡,我火速辦了婚禮鹰溜,結(jié)果婚禮上虽填,老公的妹妹穿的比我還像新娘。我一直安慰自己曹动,他們只是感情好斋日,可當我...
    茶點故事閱讀 65,430評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著墓陈,像睡著了一般恶守。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上贡必,一...
    開封第一講書人閱讀 49,764評論 1 290
  • 那天兔港,我揣著相機與錄音,去河邊找鬼赊级。 笑死押框,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的理逊。 我是一名探鬼主播橡伞,決...
    沈念sama閱讀 38,907評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼晋被!你這毒婦竟也來了兑徘?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,679評論 0 266
  • 序言:老撾萬榮一對情侶失蹤羡洛,失蹤者是張志新(化名)和其女友劉穎挂脑,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體欲侮,經(jīng)...
    沈念sama閱讀 44,122評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡崭闲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,459評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了威蕉。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刁俭。...
    茶點故事閱讀 38,605評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖韧涨,靈堂內(nèi)的尸體忽然破棺而出牍戚,到底是詐尸還是另有隱情,我是刑警寧澤虑粥,帶...
    沈念sama閱讀 34,270評論 4 329
  • 正文 年R本政府宣布如孝,位于F島的核電站,受9級特大地震影響娩贷,放射性物質(zhì)發(fā)生泄漏第晰。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,867評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望但荤。 院中可真熱鬧罗岖,春花似錦、人聲如沸腹躁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽纺非。三九已至,卻和暖如春赘方,著一層夾襖步出監(jiān)牢的瞬間烧颖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評論 1 265
  • 我被黑心中介騙來泰國打工窄陡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留炕淮,地道東北人。 一個月前我還...
    沈念sama閱讀 46,297評論 2 360
  • 正文 我出身青樓跳夭,卻偏偏與公主長得像涂圆,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子币叹,可洞房花燭夜當晚...
    茶點故事閱讀 43,472評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 官方中文版原文鏈接 感謝社區(qū)中各位的大力支持润歉,譯者再次奉上一點點福利:阿里云產(chǎn)品券,享受所有官網(wǎng)優(yōu)惠颈抚,并抽取幸運大...
    HetfieldJoe閱讀 3,028評論 3 37
  • 《ECMAScript6 入門》阮一峰 讀書筆記 let和constlet聲明的變量僅在塊級作用域內(nèi)有效踩衩,var聲...
    親愛的孟良閱讀 714評論 1 2
  • 三,字符串擴展 3.1 Unicode表示法 ES6 做出了改進贩汉,只要將碼點放入大括號驱富,就能正確解讀該字符。有了這...
    eastbaby閱讀 1,518評論 0 8
  • 1 認識他是在微博 ,因為那時候是高二升高三的那個暑假,所以每天沒事就會刷刷微博匹舞,看看學(xué)習(xí)方法褐鸥。因為學(xué)習(xí),就認識他...
    默默的小獅子閱讀 557評論 0 2
  • 昨天晚上策菜,有一位共事的伙伴要走了晶疼,走之前要去吃頓“散伙飯”。通常這樣的聚餐又憨,我心里是五味雜陳翠霍,去與不去心里都難受。...
    九月雛菊閱讀 777評論 0 16