摘要:和命令命令在聲明所在的塊級作用域內(nèi)有效。解構(gòu)賦值從數(shù)組和對象中提取值,對變量進(jìn)行賦值,這被稱為解構(gòu)。數(shù)值和布爾值的解構(gòu)解構(gòu)賦值時,如果等號右邊是數(shù)值和布爾值,則會先轉(zhuǎn)為對象。默認(rèn)值解構(gòu)賦值允許指定默認(rèn)值。
let和const命令 let命令
在聲明所在的塊級作用域內(nèi)有效。
只要塊級作用域內(nèi)存在let命令,它所聲明的變量就“綁定”(binding)這個區(qū)域,不再受外部的影響。
在同一個作用域內(nèi),不允許重復(fù)聲明變量。var可以重復(fù)聲明。
let命令不存在變量提升。var命令會發(fā)生”變量提升“現(xiàn)象。因此使用let命令聲明的變量,凡是在聲明之前就使用這些變量,就會報(bào)錯。
塊級作用域與函數(shù)聲明在塊級作用域之中聲明的函數(shù),在塊級作用域之外不可引用。
在瀏覽器的 ES6 環(huán)境中,塊級作用域內(nèi)聲明的函數(shù),行為類似于var聲明的變量。
ES6 的塊級作用域允許聲明函數(shù)的規(guī)則,只在使用大括號的情況下成立,如果沒有使用大括號,就會報(bào)錯。
應(yīng)該避免在塊級作用域內(nèi)聲明函數(shù)。如果確實(shí)需要,也應(yīng)該寫成函數(shù)表達(dá)式,而不是函數(shù)聲明語句。
const聲明的變量不得改變值。只聲明不賦值,就會報(bào)錯。
在聲明所在的塊級作用域內(nèi)有效。
不存在變量提升。
在同一個作用域內(nèi),不允許重復(fù)聲明變量。
const實(shí)際上保證的,是變量指向的那個內(nèi)存地址不得改動。因此:
對于簡單類型的數(shù)據(jù)(數(shù)值、字符串、布爾值),值就保存在變量指向的那個內(nèi)存地址,因此等同于常量。
對于復(fù)合類型的數(shù)據(jù)(主要是對象和數(shù)組),變量指向的內(nèi)存地址,保存的只是一個指針,const只能保證這個指針是固定的。
例如:
const foo = {}; // 為 foo 添加一個屬性,可以成功 foo.prop = 123; foo.prop // 123 // 將 foo 指向另一個對象,就會報(bào)錯。因?yàn)槌A縡oo儲存的是一個地址,這個地址指向一個對象。不可變的只是這個地址,即不能把foo指向另一個地址,但對象本身是可變的,所以依然可以為其添加新屬性。 foo = {}; // TypeError: "foo" is read-only頂層對象的屬性
var命令和function命令聲明的全局變量是頂層對象的屬性,即頂層對象的屬性與全局變量是等價(jià)的。
let命令、const命令、class命令聲明的全局變量,不屬于頂層對象的屬性。
解構(gòu)賦值從數(shù)組和對象中提取值,對變量進(jìn)行賦值,這被稱為解構(gòu)。解構(gòu)賦值左邊定義了要從原變量中取出什么變量。解構(gòu)賦值允許,等號左邊的模式之中,不放置任何變量名。
解構(gòu)賦值的規(guī)則是,只要等號右邊的值不是對象或數(shù)組,就先將其轉(zhuǎn)為對象。由于undefined和null無法轉(zhuǎn)為對象,所以對它們進(jìn)行解構(gòu)賦值,都會報(bào)錯。
let { prop: x } = undefined; // TypeError let { prop: y } = null; // TypeError數(shù)組解構(gòu)
數(shù)組的元素是按次序排列的,變量的取值由它的位置決定。
let [a, b, c] = [1, 2, 3];//從數(shù)組中提取值,按照對應(yīng)位置,對變量賦值
本質(zhì)上,這種寫法屬于“模式匹配”,只要等號兩邊的模式相同,左邊的變量就會被賦予對應(yīng)的值。如果解構(gòu)不成功,變量的值就等于undefined。
不完全解構(gòu):等號左邊的模式,只匹配一部分的等號右邊的數(shù)組。
let [a, [b], d] = [1, [2, 3], 4]; a // 1 b // 2 d // 4
只要某種數(shù)據(jù)結(jié)構(gòu)具有 Iterator 接口,都可以采用數(shù)組形式的解構(gòu)賦值。
對象解構(gòu)對象解構(gòu)需變量與屬性同名,才能取到正確的值。
let { foo,bar } = { foo: "aaa", bar: "bbb" }; //是let { foo: foo, bar: bar } = { foo: "aaa", bar: "bbb" };的簡寫形式 foo // "aaa" bar // "bbb" let { baz } = { foo: "aaa", bar: "bbb" }; baz // undefined
如果變量名與屬性名不一致,必須寫成下面這樣。
let { foo: baz } = { foo: "aaa", bar: "bbb" }; baz // "aaa" foo // error: foo is not defined //foo是匹配的模式,baz才是變量。真正被賦值的是變量baz,而不是模式foo。
以下語句中變量的聲明和賦值是一體的
let {foo} = {foo: 1};
let命令下面一行的圓括號是必須的,否則會報(bào)錯。因?yàn)榻馕銎鲿⑵鹗椎拇罄ㄌ枺斫獬梢粋€代碼塊,而不是賦值語句。
let foo; ({foo} = {foo: 1}); // 成功
通過解構(gòu)可以無需聲明來賦值一個變量。
({a, b} = {a: 1, b: 2}) //等同于 var {a, b} = {a: 1, b: 2}
數(shù)組本質(zhì)是特殊的對象,因此可以對數(shù)組進(jìn)行對象屬性的解構(gòu)。
let arr = [1, 2, 3]; let {0 : first, [arr.length - 1] : last} = arr;//方括號這種寫法,屬于“屬性名表達(dá)式” first // 1 last // 3字符串解構(gòu)
字符串也可以解構(gòu)賦值。這是因?yàn)榇藭r,字符串被轉(zhuǎn)換成了一個類似數(shù)組的對象。
const [a, b, c, d, e] = "hello"; a // "h" b // "e" c // "l" d // "l" e // "o"
類似數(shù)組的對象都有一個length屬性,因此還可以對這個屬性解構(gòu)賦值。
let {length : len} = "hello"; len // 5數(shù)值和布爾值的解構(gòu)
解構(gòu)賦值時,如果等號右邊是數(shù)值和布爾值,則會先轉(zhuǎn)為對象。
let {toString: s} = 123; s === Number.prototype.toString // true let {toString: s} = true; s === Boolean.prototype.toString // true //數(shù)值和布爾值的包裝對象都有toString屬性,因此變量s都能取到值.函數(shù)參數(shù)的解構(gòu)賦值
函數(shù)的參數(shù)也可以使用解構(gòu)賦值。
function add([x, y]){ return x + y; } add([1, 2]); // 3
上面代碼中,函數(shù)add的參數(shù)表面上是一個數(shù)組,但在傳入?yún)?shù)的那一刻,數(shù)組參數(shù)就被解構(gòu)成變量x和y。對于函數(shù)內(nèi)部的代碼來說,它們能感受到的參數(shù)就是x和y。
默認(rèn)值解構(gòu)賦值允許指定默認(rèn)值。如果默認(rèn)值是一個表達(dá)式,那么這個表達(dá)式是惰性求值的,即只有在用到的時候,才會求值。
let [x, y = "b"] = ["a"]; // x="a", y="b" var {x, y = 5} = {x: 1}; x // 1 y // 5
ES6 內(nèi)部使用嚴(yán)格相等運(yùn)算符(===),判斷一個位置是否有值。所以,如果一個數(shù)組成員或?qū)ο蟮膶傩灾挡粐?yán)格等于undefined,默認(rèn)值是不會生效的。
let [x = 1] = [undefined]; x // 1 let [x = 1] = [null]; x // null //數(shù)組成員是null,默認(rèn)值就不會生效,因?yàn)閚ull不嚴(yán)格等于undefined。 var {x = 3} = {x: null}; x // null
函數(shù)參數(shù)的解構(gòu)也可以使用默認(rèn)值。以下兩種寫法不一樣。
function move({x = 0, y = 0} = {}) { return [x, y]; } move({x: 3}); // [3, 0] //為變量x和y指定默認(rèn)值
function move({x, y} = { x: 0, y: 0 }) { return [x, y]; } move({x: 3}); // [3, undefined] //為函數(shù)move的參數(shù)指定默認(rèn)值模式不能使用圓括號
只有賦值語句的非模式部分,可以使用圓括號。
({ p: (d) } = {}); // 正確 let [(a)] = [1];//報(bào)錯 因?yàn)樽兞柯暶髡Z句中,不能帶有圓括號。 function f([(z)]) { return z; }// 報(bào)錯 因?yàn)楹瘮?shù)參數(shù)也屬于變量聲明,因此不能帶有圓括號。 [(b)] = [3]; // 正確 因?yàn)槟J绞侨?shù)組的第一個成員,跟圓括號無關(guān)。 ([a]) = [5]; //報(bào)錯 因?yàn)橘x值語句中,不能將整個模式,或嵌套模式中的一層,放在圓括號之中。Symbol
ES6 引入了一種新的原始數(shù)據(jù)類型Symbol,表示獨(dú)一無二的值。Symbol值通過Symbol函數(shù)生成。對象的屬性名現(xiàn)在可以有兩種類型,一種是原來就有的字符串,另一種就是新增的 Symbol 類型。凡是屬性名屬于 Symbol 類型,就都是獨(dú)一無二的,可以保證不會與其他屬性名產(chǎn)生沖突。
注意,Symbol函數(shù)前不能使用new命令,否則會報(bào)錯。這是因?yàn)?Symbol 值不是對象,所以也不能添加屬性。基本上,它是一種類似于字符串的數(shù)據(jù)類型。Symbol函數(shù)可以接受一個字符串作為參數(shù),表示對 Symbol 實(shí)例的描述。如果 Symbol 的參數(shù)是一個對象,就會調(diào)用該對象的toString方法,將其轉(zhuǎn)為字符串,然后才生成一個 Symbol 值。
var s1 = Symbol("foo"); var s2 = Symbol("bar"); s1 // Symbol(foo) s2 // Symbol(bar) s1.toString() // "Symbol(foo)" s2.toString() // "Symbol(bar)"
注意,Symbol函數(shù)的參數(shù)只是表示對當(dāng)前 Symbol 值的描述,因此相同參數(shù)的Symbol函數(shù)的返回值是不相等的。
// 沒有參數(shù)的情況 var s1 = Symbol(); var s2 = Symbol(); s1 === s2 // false // 有參數(shù)的情況 var s1 = Symbol("foo"); var s2 = Symbol("foo"); s1 === s2 // false
Symbol 值不能與其他類型的值進(jìn)行運(yùn)算,會報(bào)錯。但是,Symbol 值可以顯式轉(zhuǎn)為字符串或布爾值,但是不能轉(zhuǎn)為數(shù)值。
var sym = Symbol("My symbol"); "your symbol is " + sym // TypeError: can"t convert symbol to string String(sym) // "Symbol(My symbol)" Boolean(sym) // true Number(sym) // TypeError作為屬性名的 Symbol
由于每一個 Symbol 值都是不相等的,因此用于對象的屬性名時,就能保證不會出現(xiàn)同名的屬性。
var mySymbol = Symbol(); // 第一種寫法 var a = {}; a[mySymbol] = "Hello!"; // 第二種寫法 var a = { [mySymbol]: "Hello!" }; // 第三種寫法 var a = {}; Object.defineProperty(a, mySymbol, { value: "Hello!" }); // 以上寫法都得到同樣結(jié)果 a[mySymbol] // "Hello!"
使用 Symbol 值定義屬性時,Symbol 值必須放在方括號之中。該屬性仍是公開屬性。因此,Symbol 值作為對象屬性名時,不能用點(diǎn)運(yùn)算符。
var mySymbol = Symbol(); var a = {}; a.mySymbol = "Hello!"; a[mySymbol] // undefined a["mySymbol"] // "Hello!"
上面代碼中,因?yàn)?b>點(diǎn)運(yùn)算符后面總是字符串,所以不會讀取mySymbol作為標(biāo)識名所指代的那個值,導(dǎo)致a的屬性名實(shí)際上是一個字符串,而不是一個 Symbol 值。
Symbol 類型還可以用于定義一組常量,保證其值得唯一。Symbol 作為屬性名,該屬性不會出現(xiàn)在for...in、for...of循環(huán)中,也不會被Object.keys()、Object.getOwnPropertyNames()、JSON.stringify()返回。可使用Object.getOwnPropertySymbols方法獲取對象的所有 Symbol 屬性名。
Symbol.for(),Symbol.keyFor()Symbol.for():會先檢查給定的key是否已經(jīng)存在,如果不存在才會新建一個值,該值會被登記在全局環(huán)境中供搜索。
Symbol():沒有登記制度,因此每次調(diào)用都會返回一個不同的值。
Symbol.for("bar") === Symbol.for("bar") // true Symbol("bar") === Symbol("bar") // false var s1 = Symbol("foo"); var s2=Symbol.for("foo"); s1===s2 //false
Symbol.keyFor():返回一個已登記的 Symbol 類型值的key。
var s1 = Symbol.for("foo"); Symbol.keyFor(s1) // "foo" var s2 = Symbol("foo"); Symbol.keyFor(s2) // undefined 變量s2屬于未登記的Symbol值,所以返回undefined。
Symbol.for為Symbol值登記的名字,是全局環(huán)境的,可以在不同的 iframe 或 service worker 中取到同一個值。
內(nèi)置的Symbol值Symbol.hasInstance:對象的Symbol.hasInstance屬性,指向一個內(nèi)部方法。當(dāng)其他對象使用instanceof運(yùn)算符,判斷是否為該對象的實(shí)例時,會調(diào)用這個方法。
Symbol.isConcatSpreadable:對象的Symbol.isConcatSpreadable屬性等于一個布爾值,表示該對象使用Array.prototype.concat()時,是否可以展開。數(shù)組的默認(rèn)行為是可以展開。類似數(shù)組的對象的默認(rèn)行為是不可以展開。Symbol.isConcatSpreadable屬性等于true或undefined時,都是可以展開的。對于一個類來說,Symbol.isConcatSpreadable屬性必須寫成實(shí)例的屬性。
let arr1 = ["c", "d"]; ["a", "b"].concat(arr1, "e") // ["a", "b", "c", "d", "e"] arr1[Symbol.isConcatSpreadable] // undefined let obj = {length: 2, 0: "c", 1: "d"}; ["a", "b"].concat(obj, "e") // ["a", "b", obj, "e"] obj[Symbol.isConcatSpreadable] = true; ["a", "b"].concat(obj, "e") // ["a", "b", "c", "d", "e"]
Symbol.species:對象的Symbol.species屬性,指向當(dāng)前對象的構(gòu)造函數(shù)。創(chuàng)造實(shí)例時,默認(rèn)會調(diào)用這個方法,即使用這個屬性返回的函數(shù)當(dāng)作構(gòu)造函數(shù),來創(chuàng)造新的實(shí)例對象。
Symbol.match:對象的Symbol.match屬性,指向一個函數(shù)。當(dāng)執(zhí)行str.match(myObject)時,如果該屬性存在,會調(diào)用它,返回該方法的返回值。
String.prototype.match(regexp) // 等同于 regexp[Symbol.match](this)
Symbol.replace:對象的Symbol.replace屬性,指向一個方法,當(dāng)該對象被String.prototype.replace方法調(diào)用時,會返回該方法的返回值。
String.prototype.replace(searchValue, replaceValue) // 等同于 searchValue[Symbol.replace](this, replaceValue)
Symbol.search:對象的Symbol.search屬性,指向一個方法,當(dāng)該對象被String.prototype.search方法調(diào)用時,會返回該方法的返回值。
String.prototype.search(regexp) // 等同于 regexp[Symbol.search](this)
Symbol.split:對象的Symbol.split屬性,指向一個方法,當(dāng)該對象被String.prototype.split方法調(diào)用時,會返回該方法的返回值。
String.prototype.split(separator, limit) // 等同于 separator[Symbol.split](this, limit)
Symbol.iterator:對象的Symbol.iterator屬性,指向該對象的默認(rèn)遍歷器方法。
Symbol.toPrimitive:對象的Symbol.toPrimitive屬性,指向一個方法。該對象被轉(zhuǎn)為原始類型的值時,會調(diào)用這個方法,返回該對象對應(yīng)的原始類型值。
Symbol.toStringTag:對象的Symbol.toStringTag屬性,指向一個方法。在該對象上面調(diào)用Object.prototype.toString方法時,如果這個屬性存在,它的返回值會出現(xiàn)在toString方法返回的字符串之中,表示對象的類型。也就是說,這個屬性可以用來定制[object Object]或[object Array]中object后面的那個字符串。
Symbol.unscopables:對象的Symbol.unscopables屬性,指向一個對象。該對象指定了使用with關(guān)鍵字時,哪些屬性會被with環(huán)境排除。
參考自:ECMAScript 6 入門
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/83037.html
摘要:返回一個對象,遍歷對象自身和繼承的所有可枚舉屬性不含,與相同和在紅寶書中就已經(jīng)提到過屬性,表示的是引用類型實(shí)例的一個內(nèi)部指針,指向該實(shí)例的構(gòu)造函數(shù)的原型對象。 半個月前就決定要將ES6的學(xué)習(xí)總結(jié)一遍,結(jié)果拖延癥一犯,半個月就過去了,現(xiàn)在補(bǔ)起來,慚愧慚愧。 阮一峰的《ES6標(biāo)準(zhǔn)入門》這本書有300頁左右,除了幾個新的API和js語法的擴(kuò)展,真正有價(jià)值的內(nèi)容并不多。所謂存在即合理,每部分的...
摘要:塊級作用域只有全局作用域和函數(shù)作用域,沒有塊級作用域,這帶來了很多不合理的場景。如聲明變量的方法只有兩種聲明變量的方法命令一共有六種命令變量的解構(gòu)賦值允許按照一定的模式,從數(shù)組和對象中提取,按照位置的對應(yīng)關(guān)系對變量賦值,這被稱為解構(gòu)。 塊級作用域 es5只有全局作用域和函數(shù)作用域,沒有塊級作用域,這帶來了很多不合理的場景。 第一種場景:內(nèi)層變量可能會覆蓋外層變量 var test = ...
摘要:但是有了尾調(diào)用優(yōu)化之后,遞歸函數(shù)的性能有了提升。常被用來檢查對象中是否存在某個鍵名,集合常被用來獲取已存的信息。循環(huán)解構(gòu)對象本身不支持迭代,但是我們可以自己添加一個生成器,返回一個,的迭代器,然后使用循環(huán)解構(gòu)和。 一、let和const 在JavaScript中咱們以前主要用關(guān)鍵var來定義變量,ES6之后,新增了定義變量的兩個關(guān)鍵字,分別是let和const。對于變量來說,在ES5中...
閱讀 3407·2021-11-25 09:43
閱讀 2294·2021-09-06 15:02
閱讀 3538·2021-08-18 10:21
閱讀 3341·2019-08-30 15:55
閱讀 2344·2019-08-29 17:06
閱讀 3534·2019-08-29 16:59
閱讀 962·2019-08-29 13:47
閱讀 2756·2019-08-26 13:24