亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

ECMAScript6

MSchumi / 1264人閱讀

摘要:返回布爾值標(biāo)簽?zāi)0蹇梢跃o跟一個(gè)函數(shù)名后邊,該函數(shù)將被調(diào)用來處理這個(gè)模板字符串。其它情況下返回值為在內(nèi)部,整數(shù)和浮點(diǎn)數(shù)使用同樣的存儲(chǔ)方法,所以和被視為同一個(gè)值。

簡(jiǎn)介

ES6目標(biāo),讓JavaScript變成一個(gè)企業(yè)級(jí)的開發(fā)語言,不僅僅限制與前端頁(yè)面的腳本語言。

標(biāo)準(zhǔn)(Standard): 用于定義與其他事物區(qū)別的一套規(guī)則
實(shí)現(xiàn)(Implementation): 某個(gè)標(biāo)準(zhǔn)的具體實(shí)施/真實(shí)實(shí)踐
編譯
服務(wù)端使用 babel 編譯

構(gòu)建工具fis使用
插件:fis-parser-babel2 編譯ES6

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

TypeScript與babel編譯有區(qū)別:

例如:對(duì)一個(gè)類的編譯TypeScript編譯的結(jié)果是一個(gè)閉包類,babel編譯的結(jié)果是一個(gè)安全類.

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庫(kù)來編譯.

traceur庫(kù),引入兩個(gè)庫(kù):traceur.jstreaceur-bootstrap.js

let&const let

let聲明一個(gè)塊級(jí)作用域,并且可以初始化該變量。用法與var類似。只能在所在的代碼塊內(nèi)有效。

塊作用域:{}構(gòu)成的一個(gè)代碼庫(kù)處的作用域叫做塊作用域。

let 允許吧變量的作用域限制在塊級(jí)域中。與var 不同的是:var聲明變量要么是全局的,要么是函數(shù)級(jí)的,而無法是塊級(jí)的。

典型應(yīng)用:for循環(huán)中的計(jì)數(shù)器
let定義的變量,會(huì)在塊作用域保留下來,訪問的就是當(dāng)前循環(huán)的變量值。

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

console.log(j); // error 報(bào)錯(cuò)。
for(let i = 0; i < 5; i++){
  setTimeout(function(){
      console.log(i);
  }, i * 100);
}


作用域規(guī)則

用let定義的變量的作用域是定義它們的塊內(nèi),以及包含在這個(gè)塊中的子塊
與var區(qū)別,是否可以有塊級(jí)概念,是否有存在變量提升

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); // 報(bào)錯(cuò)ReferenceError

let a = 10;
var b = 10;

function foo(){

  a = 20;  // 報(bào)錯(cuò) ReferenceError
  console.log(a);
  
  let a = 10;
  console.log(a);
  
}
foo();

let 的暫存死區(qū)

在同一個(gè)函數(shù)或同一個(gè)作用域中的let重復(fù)定義一個(gè)變量將引入TypeError

注意:switch中聲明的變量。

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

如果塊中存在let 和const。 凡是在聲明之前就使用這些變量,就會(huì)報(bào)錯(cuò)。
let聲明之前,該變量都是不可用的。稱之為:暫時(shí)性死區(qū)(temproal dead zone簡(jiǎn)稱 TDZ)

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

  let a; // TDZ結(jié)束
  console.log(tmp); // undefined

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

ES6中的TDZ 像是運(yùn)行時(shí)的檢查而不是語法聲明上的概念.

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

let特點(diǎn):

具有塊級(jí)作用域

沒有變量提升

不允許重復(fù)聲明

具有暫時(shí)性死亡區(qū)

為了不出發(fā)死亡區(qū),必須,變量先聲明,后使用的規(guī)定。
let聲明的全局變量并不是全局對(duì)象的屬性
let聲明的變量知道控制流到達(dá)該變量被定義的代碼行時(shí)才會(huì)被裝載,所以在到達(dá)之前會(huì)使用該變量會(huì)觸發(fā)錯(cuò)誤,也就是所說的暫時(shí)性死亡區(qū)。沒有分為預(yù)解析階段。

塊級(jí)作用域的意義:
ES5中,只有全局作用域和函數(shù)作用域,沒有塊級(jí)作用域。

缺點(diǎn):
1:內(nèi)存變量可能會(huì)覆蓋外層變量。
2:用來計(jì)數(shù)的循環(huán)變量泄漏為全局變量。(循環(huán)內(nèi)變量過度共享)

const

const聲明一個(gè)只讀的常量。 一旦聲明,常量的值就不可更改。
意味著,const一旦聲明常量,就必須立即初始化,不可留到以后賦值。

語法:const key = value;

在定義常量的前面,不能訪問到常量,因此一般都將常量定義在文件的最前面。
例如:require() 模塊的時(shí)候使用。

const http = require("http");

常量不能被重復(fù)定義,為了保證常量定義使用的時(shí)候的安全性。

const 和 let 的區(qū)別:
const具有l(wèi)et的所有特性,比let更加嚴(yán)格,不可以被重復(fù)定義(賦值)。

const 只是保證變量名指向的地址不變,并不保證該地址的數(shù)據(jù)不變。所以將一個(gè)對(duì)象聲明為常量必須非常小心。

const foo = {};

foo.k1 = 100;

console.log( foo.k1 );

foo = {}; // TypeError: "foo" is read-only
// 常量foo 儲(chǔ)存的是一個(gè)地址,這個(gè)地址指向一個(gè)對(duì)象。不可變的只是這個(gè)地址,即不能把foo指向另一個(gè)地址,但是對(duì)象本身是可變的,所以依然可以為其添加新的屬性。

Objcet.freeze()
作用:凍結(jié)對(duì)象(不可為對(duì)象添加屬性和和方法)
參數(shù):被凍結(jié)的對(duì)象

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


// 常規(guī)模式時(shí),下面一行不起作用, 忽略添加 
// 嚴(yán)格模式時(shí),該行會(huì)報(bào)錯(cuò)
foo.k1 = 100;

console.log(foo);
解構(gòu)賦值

結(jié)構(gòu)的作用是可以快速取得數(shù)組或?qū)ο螽?dāng)中的元素或?qū)傩?,而無需使用arr[x]或者obj[key]等傳統(tǒng)方式進(jìn)行賦值.

數(shù)組的結(jié)構(gòu)賦值

解構(gòu):從數(shù)組和對(duì)象中提取值,對(duì)變量進(jìn)行賦值。

基本用法:

let [a, b, c] = [1, 2, 3]; // 從數(shù)組中提取值,按照對(duì)應(yīng)位置,對(duì)變量賦值。
// 這種寫法,本質(zhì)上屬于“模式匹配”。 只要等號(hào)兩邊的模式相同,左右的變量就會(huì)賦予對(duì)應(yīng)的值。

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

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

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

如果解構(gòu)不成功,變量值為undefiend。

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

不完全解構(gòu): 等號(hào)左邊的模式,只匹配一部分等號(hào)右邊的數(shù)組。

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

等號(hào)的右邊不是數(shù)組,(嚴(yán)格的說,不是可遍歷的結(jié)構(gòu)),會(huì)報(bào)錯(cuò)。

// 報(bào)錯(cuò)
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
// 轉(zhuǎn)為對(duì)象以后不具備Iterator接口(前面5個(gè)表達(dá)式), 本身就不具備Iterator接口(最后一個(gè)表達(dá)式) 

只要某種數(shù)據(jù)結(jié)構(gòu)具有Iterator接口,都可以采用數(shù)組形式的解構(gòu)賦值。 (例如:函數(shù)執(zhí)行之后的返回值)

默認(rèn)值
解構(gòu)賦值允許設(shè)置默認(rèn)值

let [a = 100] = [];

console.log(a); // 100

ES6內(nèi)部使用嚴(yán)格相等 運(yùn)算符(===),判斷一個(gè)位置是否有值。如果一個(gè)數(shù)組成員不嚴(yán)格等于undefeind,默認(rèn)值不會(huì)生效。

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

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

如果默認(rèn)值是一個(gè)表達(dá)式,這個(gè)表達(dá)式是惰性求值(只有在用到的時(shí)候才會(huì)求值)。

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

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

console.log(x); // 1 
// fn(); 函數(shù)不會(huì)執(zhí)行

默認(rèn)值可以引用其它解構(gòu)賦值的變量
默認(rèn)值可以引用解構(gòu)賦值的其它變量,但該變量必須已經(jīng)聲明,如果不聲明,將會(huì)報(bào)錯(cuò)。

let [x = 1, y = x] = []; // x = 1  y = 1
let [x = y, y = 1] = []; // ReferenceError 
// x用到默認(rèn)值y時(shí),y還沒有聲明。

最為常用的地方是:函數(shù)參數(shù)的arguments類數(shù)組對(duì)象的解構(gòu)賦值。

對(duì)象的解構(gòu)賦值

對(duì)象的解構(gòu)與數(shù)組有一個(gè)重要的不同之處,數(shù)組的元素是按次序排序,變量的取值由它的位置決定的,而對(duì)象的屬性沒有次序,變量必須與屬性同名,才能取到正確的值。

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

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

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

對(duì)象的解構(gòu)賦值的內(nèi)部機(jī)制:先找到同名屬性,然后再賦值給對(duì)應(yīng)的變量。真被賦值的是后者,而不是前者。

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

console.log(baz); // aaa
console.log(foo); // ReferenceError
// 被賦值的是變量baz,而不是模式foo

默認(rèn)值

默認(rèn)值生效的條件:對(duì)象的屬性值嚴(yán)格等于undefined。

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

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

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

如果解構(gòu)失敗,變量值等于undefined

字符串的解構(gòu)賦值

字符串的解構(gòu)賦值本質(zhì):字符串被轉(zhuǎn)為類數(shù)組對(duì)象,類數(shù)組對(duì)象中有l(wèi)ength屬性,可以有Iterator接口,可以被遍歷。

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

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

數(shù)值和布爾值的解構(gòu)賦值

需要指定包裝對(duì)象toString
解構(gòu)規(guī)則:等號(hào)右邊的值不是對(duì)象,就先將其轉(zhuǎn)為對(duì)象。 undefind 和 null 無法轉(zhuǎn)為對(duì)象,對(duì)其二者解構(gòu)賦值,都會(huì)報(bào)錯(cuò)。

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

可以解構(gòu)賦值,可以使用默認(rèn)值

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

圓括號(hào)問題

對(duì)于編譯器來說,一個(gè)式子到底是模式,,還是表達(dá)式,沒有辦法從一開始就知道,必須解析到(或解析不到)等號(hào)才能知道。
問題:模式中出現(xiàn)的圓括號(hào)怎么處理。
解析規(guī)則:只要有可能導(dǎo)致解構(gòu)的歧義,就不得使用圓括號(hào)。

建議:只要有可能,就不要再模式中放置圓括號(hào)。能不使用,就不使用圓括號(hào)。

不能使用圓括號(hào)的情況

變量聲明語句中,不能帶有圓括號(hào)
// 全部報(bào)錯(cuò)
var [(a)] = [1];

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

var { o: ({ p: p }) } = { o: { p: 2 } };
// 都是變量聲明語句,模式不能使用圓括號(hào)。


函數(shù)參數(shù)中,模式不能帶有圓括號(hào)。
// 報(bào)錯(cuò)
function f([(z)]) { return z; }    

賦值語句中,不能將整個(gè)模式,或嵌套模式中一層,放在圓括號(hào)之中。
// 全部報(bào)錯(cuò)
({ p: a }) = { p: 42 };
([a]) = [5];

可以使用圓括號(hào)的情況:
賦值語句的非模式部分,可以使用圓括號(hào)。

[(b)] = [3]; // 正確  // 模式是取數(shù)組的第一個(gè)成員,跟圓括號(hào)無關(guān)
({ p: (d) } = {}); // 正確 // 模式是p,而不是d;
[(parseInt.prop)] = [3]; // 正確 // 模式是取數(shù)組的第一個(gè)成員,跟圓括號(hào)無關(guān)
用途
交換變量的值
[x, y] = [y, x]

從函數(shù)返回多個(gè)值

函數(shù)只能返回一個(gè)值,如果要返回多個(gè)值,只能將它們放在數(shù)組或?qū)ο罄锓祷亍?/p>

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

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

// 返回一個(gè)對(duì)象

function example() {
  return {
    foo: 1,
    bar: 2
  };
}
var { foo, bar } = example();
函數(shù)參數(shù)定義

將一組參數(shù)與變量名對(duì)應(yīng)。

// 參數(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ù)

提取JSON對(duì)象中的數(shù)據(jù)

函數(shù)參數(shù)的默認(rèn)值

遍歷Map結(jié)構(gòu)

輸入模塊的指定方法

加載模塊時(shí),往往需要指定輸入那些方法。

const { SourceMapConsumer, SourceNode } = require("source-map");
String的擴(kuò)展 satrtsWith
str.starsWith(str1, num);

判斷字符串以指定參數(shù)開頭
參數(shù)1:開頭的字符
參數(shù)2:可選,指定開始查找的索引位置
返回布爾值

endWith
str.endWith(str1, num);

判斷字符串以指定參數(shù)結(jié)束
參數(shù)1:結(jié)束的字符子串
參數(shù)2:可選,指定開始查找的索引位置
返回布爾值

includes
str.includes(str1, num);

判斷指定的參數(shù)字符串是否包含在字符串中。
參數(shù)1:被查詢的字符串
參數(shù)2:可選,從那邊開始查找索引位置。
返回布爾值

標(biāo)簽?zāi)0?/b>

``可以緊跟一個(gè)函數(shù)名后邊,該函數(shù)將被調(diào)用來處理這個(gè)模板字符串。 稱之為:“標(biāo)簽?zāi)0濉?tagged template);

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

標(biāo)簽?zāi)0鍖?shí)質(zhì)并不是模板,而是函數(shù)的調(diào)用的一種特殊形式?!皹?biāo)簽”指的就是函數(shù),緊跟在后面的模板字符串就是它的參數(shù)。

如果模板字符里面有變量,就不在是簡(jiǎn)單的調(diào)用,而是會(huì)將模板字符串先處理成多個(gè)參數(shù),再調(diào)用函數(shù)。

模板字符串

語法:${表達(dá)式}
需要通過``來聲明字符串,才會(huì)生效。
如果使用""單引號(hào)聲明沒有效果。并不會(huì)解析模板中的表達(dá)式。

//let num = `十`;
let num = `5`;
let intro = `

笑一笑,${5 * 2}年少

`;
repeat

重復(fù)字符串
參數(shù):指定重復(fù)的次數(shù)

let num = "10";

let intro = `

笑一笑,${num * 2}年少

`; let introT = intro.repeat(2); console.log(intro); console.log(introT);
raw

返回原始字符串,該方法不會(huì)將字符串中的轉(zhuǎn)義字符轉(zhuǎn)義
這個(gè)方法特殊,不需要使用()調(diào)用.
是String底下的一個(gè)方法,直接通過String調(diào)用即可。

console.log("success 
 1");

let str = String.raw`success 
 1`;

console.log(str);

Number的擴(kuò)展

ES6在Number對(duì)象上,提供了Number.isFinite() 和 Number.isNaN();兩個(gè)方法。
用來檢查Infinite和NaN這兩個(gè)特殊值。

isFanite();

檢查是否是作為數(shù)字存在,對(duì)于不存在或者是NaN返回值為:false,對(duì)于數(shù)字返回值為: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

// 實(shí)現(xiàn)方式
(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();

當(dāng)參數(shù)是NaN的時(shí)候,才返回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

// 實(shí)現(xiàn)方式
(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);

與傳統(tǒng)的全局方法isFinte()方法isNaN()的區(qū)別:
傳統(tǒng)方法先調(diào)用Number()將非數(shù)值的值轉(zhuǎn)為數(shù)值,再進(jìn)行判斷。
Number.isFinte()和isNaN();只對(duì)數(shù)值有效,非數(shù)值一律返回false.

parseInt&parseFloat

ES6將全局方法parseInt();和parseFloat();方法 移植到Number對(duì)象上,行為完全保持不變。

目的:逐漸減少全局性方法,是的語言逐步模塊化。

isInteger

當(dāng)參數(shù)是正整數(shù),負(fù)整數(shù),0,-0,的時(shí)候返回值為:true。其它情況下返回值為:false
在JavaScript內(nèi)部,整數(shù)和浮點(diǎn)數(shù)使用同樣的存儲(chǔ)方法,所以3和3.0被視為同一個(gè)值。

Math的擴(kuò)展 sign

Math.sign();用來判斷一個(gè)數(shù)到底是整數(shù),負(fù)數(shù),還是零。
返回值:

參數(shù)為整數(shù),返回+1

參數(shù)為負(fù)數(shù),返回-1

參數(shù)為0 ,返回0

參數(shù)為-0,返回-0

參數(shù)為其它值,返回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(); 用于去除一個(gè)數(shù)的小數(shù)部分,返回 整數(shù)部分。

非數(shù)值,Math.trunc()內(nèi)部先使用Number();將其轉(zhuǎn)為數(shù)值。
Math.trunc(123.456); // 123
對(duì)于空值和無法截取整數(shù)的值,返回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的擴(kuò)展 form

作用:將類數(shù)組對(duì)象轉(zhuǎn)化成數(shù)組對(duì)象
參數(shù)1:類數(shù)組對(duì)象
參數(shù)2:可選,處理的回調(diào)函數(shù)??梢蕴幚眍悓?duì)象每個(gè)成員
該回調(diào)函數(shù)中參數(shù)1:value值,(類數(shù)組的成員), 參數(shù)2:索引值。返回值會(huì)保留最終結(jié)果,如果沒有返回值,那么from函數(shù)會(huì)返回由undefined構(gòu)成的一個(gè)新數(shù)組

如果是轉(zhuǎn)一個(gè)真正的數(shù)組,Array.from();會(huì)返回一個(gè)一模一樣的新數(shù)組。
更經(jīng)常的使用時(shí):arguments 和 獲取的DOM元素。

// 類數(shù)組對(duì)象
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();將一組值,轉(zhuǎn)為數(shù)組。
返回值:返回參數(shù)值組成的數(shù)組,如果沒有參數(shù),就返回一個(gè)空數(shù)組。

作用:彌補(bǔ)數(shù)組構(gòu)造函數(shù)Array()的不足。因?yàn)閰?shù)個(gè)數(shù)的不同,會(huì)導(dǎo)致Array()的行為有所差異。
Array()如果是一個(gè)參數(shù),則表示當(dāng)前數(shù)組的長(zhǎng)度。如果是二個(gè)或二個(gè)以上,則表示數(shù)組成員。

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

Array.of();基本上可以用來替代Array()或new Array(); 并且不存在由于參數(shù)不同而導(dǎo)致的重載問題。

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

// 模擬Arraay.of();方法
function ArrayOf () {
    return [].slice.call(arguments);
}

find

find();方法和findIndex();方法
find();
作用:獲取第一個(gè)符合條件的數(shù)組成員。
參數(shù):回調(diào)函數(shù)。所有的數(shù)組成員一次執(zhí)行該回調(diào)函數(shù)。知道找出一個(gè)返回值為true的成員。如果沒有符合條件的成員,則返回false。
回調(diào)函數(shù)中的參數(shù): 當(dāng)前value值,當(dāng)前索引值index(可選), 原數(shù)組arr(可選)

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

findIndex();
作用:返回第一個(gè)符合條件的數(shù)組成員的索引值,如果所有成員都不符合條件,則返回 -1.
參數(shù):和find();參數(shù)一樣是一個(gè)回調(diào)函數(shù)。

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

提出的解決問題:
indexOf();無法檢測(cè)出成員中是否有NaN

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

findIndex();搭配 Object.is(); 可以檢測(cè)出來

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

fill

使用給定值,填充一個(gè)數(shù)組。

參數(shù)1:填充的值
參數(shù)2:可選,填充的起始位置。
參數(shù)3: 可選,填充的結(jié)束位置。

keys

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

keys();
獲取數(shù)組所有成員的索引值。
返回的是一個(gè)迭代器對(duì)象。
需要通過 for-of遍歷數(shù)組迭代器

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

let Idx = colors.keys();

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

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

values();
獲取所有成員的值,返回一個(gè)數(shù)組迭代器對(duì)象。

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

let vals = colors.values();

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

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

entries();
對(duì)鍵值對(duì)的遍歷。

將數(shù)組成員的索引值以及數(shù)組成員的值,保留在一個(gè)新數(shù)組中。

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遍歷,可以手動(dòng)調(diào)用遍歷器對(duì)象的next();方法,進(jìn)行遍歷。

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} 
  
空位

數(shù)組的空位:數(shù)組的某一個(gè)位置沒有任何值。
例如:Array構(gòu)造函數(shù)返回的數(shù)組都是空位。

空位不是undefined,一個(gè)位置的值等于undefined,依然是有值的??瘴皇菦]有任何值

注意:空位不是undefiend,一個(gè)位置的值等于undefeind。依然是有值??瘴皇菦]有任何值。

0 in [undefined, undefined, undefined] // true
0 in [, , ,] // false
// 第一個(gè)數(shù)組的0號(hào)位置是有值的,第二個(gè)數(shù)組的 0 號(hào)位置沒有值。

ES5中對(duì)于空位的不一致:

forEach(), filter(), every() ,some()都會(huì)跳過空位。

map()會(huì)跳過空位,但會(huì)保留這個(gè)值

join()和toString()會(huì)將空位視為undefined,而undefined和null會(huì)被處理成空字符串。

// 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則明確將空位轉(zhuǎn)成undeinfed
由于空位的處理規(guī)則非常不統(tǒng)一,所以應(yīng)該盡量避免出現(xiàn)空位。

Object的擴(kuò)展 屬性的簡(jiǎn)潔表示

ES6允許直接寫入變量和函數(shù),作為對(duì)象的屬性和方法。
在定義一個(gè)對(duì)象的時(shí)候,如果對(duì)象的屬性與屬性值對(duì)應(yīng)的變量名同名,可以簡(jiǎn)寫屬性名。

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

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

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

// 在對(duì)象之中,只寫屬性名,不寫屬性值,這時(shí)候,屬性值等于屬性名所代表的變量。 
// 參數(shù)簡(jiǎn)寫
function Person ( name, age ) {
    return {name, age} // ES6 允許直接引入變量,不用對(duì)對(duì)象添加同名屬性
}

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

// 等同于    
function Person(name , age) {
  return {name: name, age: age};
}
// 方法的簡(jiǎn)寫
// 如果對(duì)象屬性名與對(duì)象屬性名對(duì)應(yīng)的方法名稱相同,可以省略屬性以及 function關(guān)鍵字, 像定義類中的方法一樣定義這個(gè)屬性方法。

let obj1 = {
    name: "cyan",
    age: 22,
    sayAge: function () {
        console.log(this.age); // 22
    },
    sayName () { // ES6允許定義方法的時(shí)候,可以省略方法對(duì)應(yīng)的屬性名,和 fucntion 關(guān)鍵字
        console.log(this.name); // cyan
    }
}

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

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

// 這種屬性簡(jiǎn)寫用于函數(shù)返回非常方便
function getPoint() {
  var x = 1;
  var y = 10;
  return {x, y};
}

getPoint();
// {x:1, y:10}
屬性名表達(dá)式

JavaScript語言定義對(duì)象的屬性,有兩種方式。

// 方法一
obj.foo = true;  // 標(biāo)識(shí)符作為屬性名

// 方法二
obj["a" + "bc"] = 123; // 表達(dá)式作為屬性名
// 允許定義對(duì)象時(shí)候,對(duì)對(duì)象屬性應(yīng)用表達(dá)式
let a = "num";
let b = "ber";

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

console.log( obj );

// 表達(dá)式也可以用于方法名
let obj = {
  ["h"+"ello"]() {
    return "hi";
  }
};

obj.hello() // hi

注意:屬性名表達(dá)式不能與簡(jiǎn)潔表示法同時(shí)使用,會(huì)報(bào)錯(cuò)。

// 報(bào)錯(cuò)
let a = "b";
let b = "pink";
let color = { [a] }

console.log(color);

// 正確
let a = "cyan";
let color = { [a]: "pink" }

console.log(color);
方法的name屬性

函數(shù)的name屬性,返回函數(shù)名。
對(duì)象方法也是函數(shù),,因此也有name屬性。

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

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

特殊:
bind();方法創(chuàng)造的函數(shù),name屬性返回"bound"加上原函數(shù)的名字。
Function構(gòu)造函數(shù)創(chuàng)造的函數(shù),name屬性返回"anonymous".

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

let doSomething = function () {}

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

is

Object.is();
作用判斷兩個(gè)參數(shù)是否相等。
可以判斷0-0 ,是否相等。

ES5中,比較兩個(gè)值是否相等使用:==或者===
==缺點(diǎn):自動(dòng)轉(zhuǎn)換數(shù)據(jù)類型
===缺點(diǎn):NaN不等于自身,以及0等于-0

ES6提出“Same-value equality”(同值相等)算法.
用來比較兩個(gè)值是否嚴(yán)格相等,與嚴(yán)格比較運(yùn)算符(===)的行為基本一致。

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

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

assgin

Object.assgin();
作用:用于對(duì)象合并。
將源對(duì)象(source)的所有可枚舉屬性,復(fù)制到目標(biāo)對(duì)象(target)。
參數(shù)1:目標(biāo)對(duì)象。
后面的參數(shù)都是源對(duì)象。

只拷貝源對(duì)象的自身屬性(不拷貝繼承屬性),也不拷貝不可枚舉的屬性(enumerable: false)。

如果目標(biāo)對(duì)象與源對(duì)象有同名屬性,或多個(gè)源對(duì)象有同名屬性,則后面的屬性會(huì)覆蓋前面的屬性。
如果只有一個(gè)參數(shù)對(duì)象,則返回該參數(shù)對(duì)象。

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

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

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

如果參數(shù)不是對(duì)象,則會(huì)先轉(zhuǎn)成對(duì)象然后返回。
undefeind和null無法轉(zhuǎn)成對(duì)象,作為參數(shù),會(huì)報(bào)錯(cuò)。

Object.assign(2); // Number {[[PrimitiveValue]]: 2}
Object.assign(undefined) // 報(bào)錯(cuò)
Object.assign(null) // 報(bào)錯(cuò)

Object.assign();是淺拷貝,而不是深拷貝。如果源對(duì)象某個(gè)屬性的值是對(duì)象,那么目標(biāo)對(duì)象拷貝得到的是這個(gè)對(duì)象的引用。

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用途

為對(duì)象添加屬性
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類的對(duì)象實(shí)例。

為對(duì)象添加方法
Object.assign(Some.prototype, {
    someMethod1 ( arg1, arg2 ) {
        // ....
    }
    someMethod2 ( arg1, arg2 ) {
        // ....
    }
})


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


克隆對(duì)象
function clone(origin) {
  return Object.assign({}, origin);
}    
// 將原對(duì)象拷貝到一個(gè)空對(duì)象,得到了原始對(duì)象的克隆。


合并多個(gè)對(duì)象

將多個(gè)對(duì)象合并到某個(gè)對(duì)象,可以是空對(duì)象中(合并之后返回新的對(duì)象)

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


屬性遍歷

ES6中共有5中可以遍歷屬性的方法:

for-in
for-in循環(huán)遍歷對(duì)象吱聲和繼承的可枚舉的屬性(不含Symbol屬性)。

Object.keys(obj)
Object.keys返回一個(gè)數(shù)組,包括對(duì)象自身的(不含繼承)所有可枚舉屬性(不含Symbol屬性)

Oject.getOwnPropertyNames(obj);
Object.getOwnPropertyNames(); 返回一個(gè)數(shù)組,包含對(duì)象自身的所有屬性(不含Symbol屬性,但是包括不可枚舉屬性)

Object.getOwnPropertySymbols(obj);
Object.getOwnPropertySymbols();返回一個(gè)數(shù)組,包含對(duì)象自身的所有Symbol屬性。

Reflect.ownKeys(obj);
Reflect.ownKeys(obj);返回一個(gè)數(shù)組,包含對(duì)象自身的所有屬性,不管是屬性名Symbol或字符串,也不管是否可枚舉

遍歷規(guī)則:

首先遍歷所有屬性為數(shù)值的屬性,按照數(shù)字排序。

其次遍歷所有屬性名為字符串的屬性,按照生成時(shí)間排序。

最后遍歷所有屬性名為Symbol值的屬性,按照生成時(shí)間排序。

keys&values&entries

Object.keys();
作用: 參數(shù)對(duì)象自身的(不含繼承的) 所有可遍歷屬性的鍵名。
返回?cái)?shù)組

Object.values();
作用:參數(shù)對(duì)象自身的(不含繼承的) 所有可遍歷屬性的鍵值。
返回?cái)?shù)組

Object.entries();
作用:參數(shù)對(duì)象自身的(不含繼承的) 所有可遍歷屬性的鍵值對(duì)數(shù)組。
返回?cái)?shù)組

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

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

ES6引入Symbol的原因:根本上防止屬性名的沖突。

ES6引入一種新的原始數(shù)據(jù)類型Symbol,表示獨(dú)一無二的值。
它是JavaScript語言的第七種中數(shù)據(jù)類型。前六中是:Undefiend,Null,布爾值(Boolean),字符串(String),數(shù)值(Number),對(duì)象(Object)

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

Symbol值通過Symbol函數(shù)生成。
對(duì)象的屬性名可以有兩種類型,一種是:string。 一種是:Symbol。(凡是屬性名屬于Symbol類型,就是獨(dú)一無二,可以保證不會(huì)與其它屬性名產(chǎn)生沖突)

注意:Symbol函數(shù)前不能使用new關(guān)鍵字,否則會(huì)報(bào)錯(cuò)。因?yàn)椋篠ymbol是一個(gè)原始類型的值,不是對(duì)象。由于Symbol值不是對(duì)象,所以不能添加屬性?;旧?,它是一種類似于字符串的數(shù)據(jù)類型。

Symbol函數(shù)可以接收一個(gè)字符串作為參數(shù),表示對(duì)Symbol實(shí)例的描述,
作用:控制臺(tái)顯示或轉(zhuǎn)為字符串時(shí),比較容易區(qū)分。

返回值不相等

注意:Symbol函數(shù)的參數(shù)只是表示對(duì)當(dāng)前Symbol值的描述,因此相同參數(shù)的Symbol函數(shù)的返回值是不相等的。

// 沒有參數(shù)
let s1 = Symbol();
let s2 = Symbol(); 

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

// 參數(shù)
let s3 = Symbol("a");
let s4 = Symbol("b");

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

不能與其它類型值進(jìn)行運(yùn)算

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

可以顯示轉(zhuǎn)換為String,Boolean。(注意:不能夠轉(zhuǎn)為數(shù)值類型)

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與字符串的區(qū)別:

獨(dú)一無二

值不相等

不可與其它類型值進(jìn)行運(yùn)算

作為屬性名Symbol

由于每個(gè)Symbol值都是不相等的,意味著Symbol值可以作為標(biāo)識(shí)符。
用于對(duì)象的屬性名,就能保證不會(huì)出現(xiàn)同名的屬性。 對(duì)于一個(gè)對(duì)象由多個(gè)模塊構(gòu)成的模塊情況,能防止某一個(gè)鍵被不小心改寫或覆蓋。

Symbol值作為屬性名時(shí),是公開屬性,而不是私有屬性。

let mySymbol = Symbol("a");

// 第一種方法
let a = {};
a[mySymbol] = "hello";

// 第二種寫法
let b = {
    [mySymbol]: "hell2"
};
// 在對(duì)象的內(nèi)部,使用Symbol值定義屬性時(shí),Symbol值必須放在方括號(hào)之中。

// 第三種寫法
let c = {};
Object.defineProperty(c, mySymbol, {
    value: "hello3"
});

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

注意:Symbol值作為對(duì)象的屬性名,不能使用點(diǎn)語法。

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");
消除魔術(shù)字符串

魔術(shù)字符串:在代碼之中出現(xiàn)多次,與代碼形成強(qiáng)耦合的某一個(gè)具體的字符串或者數(shù)值。
缺點(diǎn):不利于將來的維護(hù)和修改。

消除魔術(shù)字符串的方法:把它寫成一個(gè)變量,或者常量。
變量或者常量等于那個(gè)值并不重要,只要確保不會(huì)跟其它的屬性沖突即可。

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作為屬性名,該屬性不會(huì)出現(xiàn)在for-in, for-of循環(huán)中,也不會(huì)被Object.kes();. Object.getOwnProperTyNames();返回。
Symbol并不是私有屬性,ES6中提供Object.getOwnPropertySymbols();

Object.getOwnPropertySymbols();
作用:獲取指定對(duì)象的所有Symbol屬性名。
返回一個(gè)數(shù)組。成員是當(dāng)前對(duì)象的所有用作屬性名的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();
作用:返回所有類型的鍵名,包括常規(guī)鍵名和Symbol鍵名。

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

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

以Symbol值作為名稱的屬性,不會(huì)被常規(guī)方法遍歷得到。可以為對(duì)象定義一些非私有的,但又希望只用于內(nèi)部的方法。造成一種非私有話的內(nèi)部的效果。

Symbol.for(),Symbol.keyFor()

Symbol.for();
作用:使用同一個(gè)Symbol的值。
參數(shù):一個(gè)字符串。
過程:接收一個(gè)字符串后,搜索有沒有以該參數(shù)作為名稱的Symbol值。如果有,就返回這個(gè)Symbol值,否則就新建并返回一個(gè)以該字符串為名稱的Symbol值。(具有登記機(jī)制,被登記的會(huì)在全局環(huán)境中供搜索)

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

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

Symbol.keFor();
返回:一個(gè)已經(jīng)登記的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模式:指的是調(diào)用一個(gè)類,任何時(shí)候返回的都是同一個(gè)實(shí)例。

對(duì)于 Node 來說,模塊文件可以看成是一個(gè)類。怎么保證每次執(zhí)行這個(gè)模塊文件,返回的都是同一個(gè)實(shí)例呢?

很容易想到,可以把實(shí)例放到頂層對(duì)象global。

對(duì)于Node來說,模塊文件可以看成是一個(gè)類。怎么保證每次執(zhí)行這個(gè)模塊文件,都是返回同一個(gè)實(shí)例呢? 可以把實(shí)例掛載到頂層對(duì)象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作用:修改某些操作的默認(rèn)行為。 在目標(biāo)對(duì)象之前設(shè)置屏障,外界對(duì)該對(duì)象的訪問,都必須先通過這層攔截,來保護(hù)該對(duì)象(內(nèi)部的屬性,狀態(tài),方法,行為等等)。(Proxy的操作等同于在語言層面做出修改,所以屬性一種“元編程”,即對(duì)編程語言進(jìn)行編程)

提供一種機(jī)制,可以對(duì)外界的訪問進(jìn)行過濾和改寫。
Proxy這個(gè)詞的原意是代理,這里表達(dá)hi由它來“代理”某些操作,可以譯為“代理器”。

語法: new Proxy(代理對(duì)象, 屏蔽對(duì)象);

屏障的方法,比較特殊,并不是任意定,只能通過get來獲取代理對(duì)象的信息,set來設(shè)置原始對(duì)象的額信息。但是它們不是直接處理對(duì)象的,在處理之前會(huì)過濾一些人為操作。屏蔽對(duì)象配置攔截行為(對(duì)于每一個(gè)被代理的操作,需要提供一個(gè)對(duì)應(yīng)的處理函數(shù),該函數(shù)將攔截對(duì)應(yīng)的操作。)

get();
參數(shù):target,key,receiver

set();
參數(shù):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起作用,必須針對(duì)Proxy實(shí)例進(jìn)行操作, 而不是針對(duì)目標(biāo)對(duì)象進(jìn)行操作。
如果屏蔽對(duì)象沒有進(jìn)行任何攔截操作,那就等同于直接通過原對(duì)象,操作原對(duì)象

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

let proxy = new Proxy(a, b);

proxy.tag = "javascript";

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

將Proxy對(duì)象,可以設(shè)置到Object.proxy屬性上,從而達(dá)到可以從Object對(duì)象上調(diào)用。
Proxy實(shí)例可以作為其他對(duì)象的原型對(duì)象。

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

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

let obj = Object.create(proxy);

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

同一個(gè)攔截器函數(shù),可以設(shè)置多個(gè)操作。

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攔截器操作函數(shù)

對(duì)于可以設(shè)置,但沒有設(shè)置攔截的操作,則直接落在目標(biāo)對(duì)象上,按照原先的方式產(chǎn)生結(jié)果。

get()
攔截對(duì)象屬性的讀取

set()
攔截對(duì)象屬性的設(shè)置

has(target, propKey)
攔截propKey in proxy的操作,以及對(duì)象的hasOwnProperty();
返回值:布爾值。

判斷對(duì)象是否具有某個(gè)屬性時(shí),方法才會(huì)生效。典型的操作就是in運(yùn)算符。
使用has方法隱藏某些屬性,不被in運(yùn)算符發(fā)現(xiàn)

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)
參數(shù)args:目標(biāo)對(duì)象的參數(shù)數(shù)組。
攔截Proxy實(shí)例作為函數(shù)調(diào)用的操作,比如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)
攔截作為構(gòu)造函數(shù)調(diào)用的操作。 比如: new Proxy(...args)

攔截函數(shù)和PHP中的魔術(shù)方法有相同的原理,當(dāng)一定條件下,會(huì)觸發(fā)該聲明的函數(shù)。

Reflect概述

Reflect對(duì)象與Proxy對(duì)象一樣
為了操作對(duì)象而提供的新API

設(shè)計(jì)目的:

將Object對(duì)象的一些明顯屬性語言內(nèi)部的方法(比如Object.defiendProerty),放到Reflect對(duì)象上,現(xiàn)階段,某些方法同時(shí)在Object和Reflect對(duì)象上部署,未來的新方法將只部署在Reflect對(duì)象上。

修改某Object方法的返回結(jié)果,讓其變得更合理。

讓Object操作都變成函數(shù)行為
比如: delete obj[name] 和 name in obj 的指令式操作

Reflect對(duì)象的方法與Proxy對(duì)象的方法一一對(duì)應(yīng),只要是Proxy對(duì)象的方法,就能在Reflect對(duì)象上找到對(duì)應(yīng)的方法。

函數(shù)的擴(kuò)展 參數(shù)的默認(rèn)值

ES5的默認(rèn)參數(shù)做法

如果沒有if判斷,參數(shù)是否被賦值,如果沒有,再等于默認(rèn)值
原因:如果參數(shù)賦值了,但是對(duì)應(yīng)值是false,則該賦值就不應(yīng)該起作用。 例如:調(diào)用的時(shí)候log("hello", ""); 如果參數(shù)是空字符串,就不應(yīng)該被改為默認(rèn)值。

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使用默認(rèn)參數(shù),直接寫在參數(shù)定義的后邊。
好處:
1:易閱讀代碼
2:利于未來的代碼優(yōu)化。未來的版本在對(duì)外接口中,測(cè)底拿掉這個(gè)參數(shù),也不會(huì)導(dǎo)致以前的代碼無法執(zhí)行。

特點(diǎn):參數(shù)變量時(shí)默認(rèn)聲明的,不能用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}

參數(shù)默認(rèn)的位置

一般的,定義默認(rèn)值的參數(shù),應(yīng)該是函數(shù)的尾參數(shù)。這樣可以比較容易看出來,到底省略了哪些參數(shù)。

如果非尾參數(shù)設(shè)置默認(rèn)值,這個(gè)參數(shù)是沒法省略。(想使用默認(rèn)值,設(shè)置為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,將觸發(fā)該參數(shù)等于默認(rèn)值, 
console.log( fn(null, 1) ); // [null, 1] // 如果傳入null,則會(huì)輸出。
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 

函數(shù)的length屬性

length屬性的含義:該函數(shù)預(yù)期傳入的參數(shù)個(gè)數(shù)。

指定了默認(rèn)值后,length屬性將失真。將返回沒有指定默認(rèn)參數(shù)的個(gè)數(shù)。
某個(gè)參數(shù)指定了默認(rèn)值以后,預(yù)期傳入的參數(shù)個(gè)數(shù)就不包括這個(gè)參數(shù)了。rest參數(shù)不會(huì)計(jì)入length屬性個(gè)數(shù)中。

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

作用域

如果參數(shù)默認(rèn)值是一個(gè)變量,則該變量所處的作用域,與其它變量的作用規(guī)則是一樣的,即先是當(dāng)前函數(shù)的作用域,然后才是全局作用域。

var x = 1;

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

fn(2); // 2    

如果參數(shù)默認(rèn)值是一個(gè)函數(shù)
該函數(shù)的作用域是其聲明時(shí)所在的作用域

let foo = "outer";

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

bar();
// 函數(shù)bar的參數(shù)func的默認(rèn)值是一個(gè)匿名函數(shù),返回值為變量foo。這個(gè)匿名函數(shù)聲明時(shí),bar函數(shù)的作用域還沒有形成,所以匿名函數(shù)里面的foo指向外層作用域foo

應(yīng)用
利用參數(shù)默認(rèn)值,可以指定某一個(gè)參數(shù)不得省略,如果省略就拋出一個(gè)錯(cuò)誤。

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

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

foo(); // 拋出錯(cuò)誤

可以將參數(shù)默認(rèn)值設(shè)置為unfeined,表明這個(gè)參數(shù)是可以省略的。

function foo ( options = undefined ) {

}
rest參數(shù)

語法:...變量名
作用:把逗號(hào)隔開的值序列組合成一個(gè)數(shù)組

獲取過來的是數(shù)組,將制定的多余變量放入數(shù)組中。

使用rest參數(shù)就不需要使用arugments對(duì)象

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

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

注意:rest參數(shù)之后不能再有其它參數(shù)(即只能是最后一個(gè)參數(shù))

擴(kuò)展運(yùn)算符

擴(kuò)展運(yùn)算符...。
好比rest參數(shù)的逆運(yùn)算。

作用:把數(shù)組或類數(shù)組對(duì)象展開成一系列用逗號(hào)隔開的值(將一個(gè)數(shù)組轉(zhuǎn)為用逗號(hào)分隔的參數(shù)序列).

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

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

一般的,主要用于函數(shù)調(diào)用:

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

let nums = [10, 20];

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

擴(kuò)展運(yùn)算符與正常的函數(shù)參數(shù),rest參數(shù)可以配合使用,體現(xiàn)靈活性。

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

let args = [1, 2];

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

擴(kuò)展運(yùn)算符的應(yīng)用

合并數(shù)組
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] );
與解構(gòu)賦值結(jié)合

擴(kuò)展運(yùn)算符與解構(gòu)賦值結(jié)合起來使用,用于生成數(shù)組。
注意:擴(kuò)展運(yùn)算符只能放在參數(shù)的最后一位。(否則將會(huì)報(bào)錯(cuò))

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


函數(shù)返回值

JavaScript的函數(shù)只能返回一個(gè)值,如果需要返回多個(gè)值,只能返回?cái)?shù)組或?qū)ο?。擴(kuò)展運(yùn)算符提供變通方法。

字符串

擴(kuò)展運(yùn)算符可以將字符串轉(zhuǎn)為數(shù)組

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

實(shí)現(xiàn)了Iterator接口的對(duì)象

任何Iterator接口對(duì)象,都可以使用擴(kuò)展運(yùn)算符轉(zhuǎn)為真正的數(shù)組
例如:arguments對(duì)象,nodeList對(duì)象

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屬性

函數(shù)的name屬性,返回該函數(shù)的屬性名。
屬性被瀏覽器支持,到ES6才寫入規(guī)范中。

ES5中匿名函數(shù),name屬性會(huì)返回空字符串。
ES6中匿名函數(shù),name屬性會(huì)返回實(shí)際的函數(shù)名

ES5,ES6中,有名的匿名函數(shù),name屬性返回具有函數(shù)名的名字

Function 構(gòu)造函數(shù)返回函數(shù)實(shí)例, 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 構(gòu)造函數(shù)
console.log( (new Function).name ); // "anonymouse";
箭頭函數(shù)

基本用法

使用 => 定義函數(shù)
() => 表達(dá)式
參數(shù) => 表達(dá)式

var f = v => v;
// 等價(jià)
var  f = function ( v ) {
    return v;
}

如果箭頭函數(shù)需要多個(gè)參數(shù)或者不需要參數(shù),可以使用()代表參數(shù)。

() => { 函數(shù)體 }

var fn = () => 5;

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



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

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

箭頭函數(shù)返回對(duì)象,需要在對(duì)象外加()

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

箭頭函數(shù)與變量解構(gòu)賦值,rest參數(shù)搭配使用

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

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

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

箭頭函數(shù)使用注意點(diǎn)

函數(shù)體內(nèi)的this對(duì)象,就是定義時(shí)所在的對(duì)象,而不是使用時(shí)所在的對(duì)象。

不可以當(dāng)作構(gòu)造函數(shù),也就是不可以使用new關(guān)鍵字。否則會(huì)拋出一個(gè)錯(cuò)誤。(names is not a constrtucor)

不可以使用arguments對(duì)象,因?yàn)閍rguments對(duì)象不存在函數(shù)體內(nèi)

不可以使用yield命令, 因此箭頭函數(shù)不能作用Generator函數(shù)。

this固定

this對(duì)象在箭頭函數(shù)中,是固定的。

this的指向固定化,有利于封裝回調(diào)函數(shù)。
this指向固定化,并不是因?yàn)榧^函數(shù)內(nèi)部有綁定this的機(jī)制,實(shí)際原因是箭頭函數(shù)根本沒有自己的this。導(dǎo)致內(nèi)部的this就是外層代碼塊的this。正是因?yàn)樗鼪]有this,所以也就不能夠作為構(gòu)造函數(shù)。

箭頭函數(shù)的this永遠(yuǎn)指向定義的時(shí)候的作用域,在各對(duì)象中定義,就指向那個(gè)對(duì)象。
當(dāng)使用call()和apply()方法更改作用于時(shí)候,箭頭函數(shù)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 });
// 箭頭函數(shù)導(dǎo)致this總是只想函數(shù)定義生效時(shí)所在的對(duì)象

對(duì)比箭頭函數(shù)的setTimeout和ES5版本的普通回調(diào)函數(shù):

// 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中清楚的說明了,箭頭函數(shù)里面根本沒有自己的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()()();   

箭頭函數(shù)中不存在:this,argumetns, super,new.target.相應(yīng)的指向外層函數(shù)的對(duì)應(yīng) this,argumetns, super,new.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]);

箭頭函數(shù)嵌套

箭頭函數(shù)的嵌套:具有管道機(jī)制(前一個(gè)函數(shù)的輸出是后一個(gè)函數(shù)的輸入)。

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

尾調(diào)用

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

function fn (x) {
    return g(x); // 函數(shù)的最后一步調(diào)用函數(shù) g() ,就是指的尾調(diào)用
}

// 不屬于為調(diào)用的情形
function f1 ( x ) {
    let y = g(x);
    return y;    
}
// 調(diào)用函數(shù)  g(x) 之后,還有賦值操作。

function f2 (x) {
    return g(x) + 1; 
}
// 調(diào)用之后還有其它操作

function f3 ( x ) {
    g(x);
}
// f3 最后是返回 undefined


// 尾調(diào)用不一定要出現(xiàn)在函數(shù)的尾部

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

尾調(diào)用優(yōu)化

尾調(diào)用特殊之處:與其它調(diào)用不同的,在于它特殊的調(diào)用位置。

函數(shù)調(diào)用會(huì)在內(nèi)存形成一個(gè)“調(diào)用記錄”,又稱“調(diào)用幀” (call frame),保存調(diào)用位置和內(nèi)部變量等信息。
如果在函數(shù)A的內(nèi)部調(diào)用函數(shù)B,那么在A的調(diào)用幀上方,還會(huì)形成一個(gè)B的調(diào)用幀。等到B運(yùn)行結(jié)束,將結(jié)果返回到A,B的調(diào)用幀才會(huì)消失。如果函數(shù)B內(nèi)部還調(diào)用函數(shù)C,那就還有一個(gè)C的調(diào)用幀,以此推類。所有的調(diào)用幀,就形成一個(gè)“調(diào)用?!?call stack)

尾調(diào)用由于是函數(shù)的最后一步操作,所以不需要保留外層函數(shù)的調(diào)用幀,因?yàn)檎{(diào)用位置,內(nèi)部變量等信息都不會(huì)再使用到。只要直接用內(nèi)層函數(shù)的調(diào)用幀,取代外層函數(shù)的調(diào)用幀就可以。

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

function fn () {
    let m = 1;
    let n = 2;
    return g(m+n); // 執(zhí)行到這一步,完全可以刪除fn()的調(diào)用幀,只保留 g(3)  的調(diào)用幀
}

fn();

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

fn();

// 等同于
g(3);

// “尾調(diào)用優(yōu)化”: 只保留內(nèi)層函數(shù)的調(diào)用幀。

如果所有函數(shù)都是尾調(diào)用,那么完全可以做到每次執(zhí)行時(shí),調(diào)用幀只有一項(xiàng),效果就大大節(jié)省內(nèi)存。

注意:只有不再用到外層函數(shù)的內(nèi)部變量,內(nèi)層函數(shù)的調(diào)用幀才會(huì)取代外層函數(shù)的調(diào)用幀,否則就無法進(jìn)行“尾調(diào)用優(yōu)化”

尾遞歸

函數(shù)調(diào)用自身,稱為遞歸,如果尾調(diào)用自身,就稱之為:尾遞歸。

遞歸非常消耗內(nèi)存,因?yàn)樾枰瑫r(shí)保存成千上百個(gè)調(diào)用幀,很容易發(fā)生"棧溢出"錯(cuò)誤(stack voerflow).但是對(duì)于尾遞歸來說,由于只存在一個(gè)調(diào)用幀,所以不會(huì)發(fā)生"棧溢出"錯(cuò)誤。

// 對(duì)比階乘  使用尾遞歸 和 不使用尾遞歸的情形

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

遞歸函數(shù)的改寫

尾遞歸的實(shí)現(xiàn),往往需要改寫遞歸函數(shù),確保最后一步只調(diào)用自身。做到這一點(diǎn)的方法,就是把所有用到的內(nèi)部變量改寫成函數(shù)的參數(shù)。

方法1:是在尾遞歸函數(shù)之外,再提供一個(gè)正常形式的函數(shù)。

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:函數(shù)柯里化
柯里化:將多參數(shù)的函數(shù)轉(zhuǎn)換成單參數(shù)的形式。(函數(shù)式編程的重要概念)

方法3:ES6的函數(shù)默認(rèn)值

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

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

遞歸本質(zhì)上是一種循環(huán)操作。純粹的函數(shù)式編程語言沒有循環(huán)操作命令,所有的循環(huán)都是使用遞歸實(shí)現(xiàn)。
對(duì)于支持“尾調(diào)用優(yōu)化”的語言,只需要知道循環(huán)可以用遞歸代替。
如果一旦使用遞歸,就最好使用尾遞歸。

尾遞歸只在嚴(yán)格模式下有效果

正常模式下:函數(shù)內(nèi)部有兩個(gè)變量,可以跟蹤函數(shù)的調(diào)用棧。

func.argumetns : 返回調(diào)用時(shí)函數(shù)的參數(shù)
func.caller: 返回調(diào)用當(dāng)前函數(shù)的那個(gè)函數(shù)。

尾遞歸優(yōu)化生效的時(shí)候,函數(shù)的調(diào)用棧會(huì)改寫,因此argumetns,caller會(huì)失真。嚴(yán)格模式下禁用這兩個(gè)變量。 所以尾遞歸模式僅在嚴(yán)格模式下生效。

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

基本用法

Set對(duì)象是ES6中新增的一種表示集合的數(shù)據(jù)結(jié)構(gòu)。它類似于數(shù)組,但是成員的值都是唯一的。沒有重復(fù)的值。

Set本身是一個(gè)構(gòu)造函數(shù),需要通過new關(guān)鍵字來生成。

Set函數(shù)可以接受一個(gè)數(shù)組(或類似數(shù)組的對(duì)象)作為參數(shù),用來初始化。
得到的實(shí)例化對(duì)象是去重復(fù)的Set對(duì)象。

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實(shí)例的屬性和方法

Set結(jié)構(gòu)的實(shí)例屬性:

Set.prototype.constructor:構(gòu)造函數(shù),默認(rèn)就是Set函數(shù)
Set.prototype.size: 返回Set實(shí)例的成員總數(shù)

Set實(shí)例方法分為:操作方法(用于操作數(shù)據(jù)) 和遍歷方法(用于遍歷成員)

操作方法

add(value): 添加某個(gè)值,返回Set結(jié)構(gòu)本身。

delete(value):刪除某個(gè)值,返回一個(gè)布爾值,表示是否刪除成功。

has(value):返回一個(gè)布爾值,表示該值是否為Set成員。

cleart(): 清除所有成員,沒有返回值。

Array.form()可以將Set結(jié)構(gòu)轉(zhuǎn)為數(shù)組。

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(); 返回鍵值對(duì)的迭代器。

forEach(); 使用回調(diào)函數(shù)遍歷每個(gè)成員。

Set結(jié)構(gòu)的遍歷順序是插入順序。 使用場(chǎng)景比如:使用Set結(jié)構(gòu)保存一個(gè)回調(diào)函數(shù)列表,調(diào)用的時(shí)候,就能夠保證按照添加順序調(diào)用。

由于Set結(jié)構(gòu)沒有鍵名,只有鍵值(或者說鍵名和鍵值是同一個(gè)值)。 所以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結(jié)構(gòu)的實(shí)例默認(rèn)可遍歷,它的默認(rèn)遍歷器生成函數(shù)就是它values方法。

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

遍歷的應(yīng)用

數(shù)組去重

擴(kuò)展運(yùn)算符(...) 內(nèi)部使用 for -of循環(huán)

實(shí)現(xiàn)交集,并集,差集。

與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}


            
                     
             
               

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/86474.html

相關(guān)文章

  • ECMAScript6 后建議的優(yōu)化語法

    摘要:是制定的的規(guī)范,代表發(fā)表的新版本,等以此類推。持續(xù)優(yōu)化更新變量聲明用于聲明常量,變量建議使用命令,建議不再使用命令,聲明的是全局變量,而則為局部變量。聲明的是全局變量也是頂層對(duì)象的屬性,則沒有綁定到頂層對(duì)象。 ECMAScript6 是 ECMA 制定的 JavaScript 的規(guī)范,ES6代表2016發(fā)表的新版本,ES7、ES5等以此類推。 (持續(xù)優(yōu)化更新) 變量聲明 cons...

    liaosilzu2007 評(píng)論0 收藏0
  • ECMAScript6 新特性——“l(fā)et和const命令”

    摘要:基本用法所聲明的變量,只在命令所在的代碼塊內(nèi)有效。在循環(huán)中適合使用不存在變量提升不像那樣會(huì)發(fā)生變量提升現(xiàn)象暫時(shí)性死區(qū)只要塊級(jí)作用域內(nèi)存在命令,它所聲明的變量就綁定這個(gè)區(qū)域,不再受外部的影響。塊級(jí)作用域?qū)嶋H上為新增了塊級(jí)作用域。 1 let 基本用法 所聲明的變量,只在let命令所在的代碼塊內(nèi)有效。 { let b = 100; console.log(b); //100...

    PascalXie 評(píng)論0 收藏0
  • ECMAScript6:官方最新Decorator修飾器構(gòu)造函數(shù)重寫了。。。

    摘要:改變發(fā)布了最新版本,最新版本的模塊名稱都改成前綴,具體可前往英文官網(wǎng)查看,中文網(wǎng)站文檔尚未更新插件包都已更換名稱,以官網(wǎng)為準(zhǔn),不然會(huì)報(bào)錯(cuò)構(gòu)造函數(shù)完全更改,一臉懵逼原先個(gè)參數(shù)改為一個(gè)對(duì)象參數(shù),參數(shù)字段具體如下圖具體查看介紹新的寫法根據(jù)最 改變 babel發(fā)布了最新版本,npm最新版本的模塊名稱都改成@babel前綴,具體可前往babel英文官網(wǎng)查看,中文網(wǎng)站文檔尚未更新 插件 plug...

    王陸寬 評(píng)論0 收藏0
  • ECMAScript6(9):正則表達(dá)式的擴(kuò)展

    摘要:正則表達(dá)式擴(kuò)展構(gòu)造函數(shù)支持傳入正則得到拷貝,同時(shí)可以用第二參修改修飾符引入新的修飾符中的修飾符有個(gè)加上的修飾符,一共個(gè)修飾符描述描述多行模式忽略大小寫模式全局匹配模式模式粘連模式模式為了兼容自己我們需要在一下情況使用該模式情況很明顯這個(gè)是不 正則表達(dá)式擴(kuò)展 構(gòu)造函數(shù)支持傳入正則得到拷貝,同時(shí)可以用第二參修改修飾符 var reg = /^abc/ig; var newReg_ig = ...

    Donne 評(píng)論0 收藏0
  • ECMAScript6(4):字符串類型擴(kuò)展

    字符串?dāng)U展 //ES6 u{20BB7} //

    IntMain 評(píng)論0 收藏0
  • ECMAScript6學(xué)習(xí)筆記

    摘要:筆記和和是塊作用域的,是聲明常量用的。一個(gè)對(duì)象如果要有可被循環(huán)調(diào)用的接口,就必須在的屬性上部署遍歷器生成方法原型鏈上的對(duì)象具有該方法也可。這種方式會(huì)訪問注冊(cè)表,其中存儲(chǔ)了已經(jīng)存在的一系列。這種方式與通過定義的獨(dú)立不同,注冊(cè)表中的是共享的。 ECMAScript6 筆記 let 和 const let和const是塊作用域的 ,const是聲明常量用的。 {let a = 10;} a ...

    CODING 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

MSchumi

|高級(jí)講師

TA的文章

閱讀更多
最新活動(dòng)
閱讀需要支付1元查看
<