摘要:在語法中,操作符有兩種意義剩余語法,參數和展開語法,展開數組對象,作為函數數組對象的擴展運算符。使用和參數進行操作其余參數傳給原始函數展開語法運算則可以看作是參數的逆運算。
在ES6語法中,...操作符有兩種意義:rest(剩余語法,rest參數) 和 spread(展開語法,展開數組/對象),作為函數、數組、對象的擴展運算符。
從某種意義上說,剩余語法與展開語法是相反的:剩余語法 rest參數
剩余語法將多個元素收集起來并“凝聚”為單個元素,而展開語法則是將數組/對象展開為其中的各個元素。
形式為(...變量名),將一個不定數量的參數表示為一個數組。用于獲取函數實參中的多余參數,組成一個數組,這樣就不需要使用arguments對象了。
語法
function(a, b, ...theArgs) { // ... }
rest參數之后不能再有其他參數(只能是最后一個參數)否則會報錯。
函數的length屬性不包括rest參數。
(function(a,b,...c){}).length //2
一個實例
function sumOnlyNumbers() { var args = arguments; var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); function filterNumbers() { return Array.prototype.filter.call(args, element => typeof element === "number" ); } } sumOnlyNumbers(1, "Hello", 5, false); // => 6
缺點: 首先我們要將arguments分配給給一個臨時新變量args,這樣才能在內部函數filterNumbers中可以訪問args新變量,因為 filterNumbers()定義了它自己的arguments 會覆蓋外部的arguments 。這種做法太冗余了。
優化: 使用rest操作符可以靈活解決這個問題,允許在函數中定義一個rest參數 ...args:
function sumOnlyNumbers(...args) { var numbers = filterNumbers(); return numbers.reduce((sum, element) => sum + element); function filterNumbers() { return args.filter(element => typeof element === "number"); } } sumOnlyNumbers(1, "Hello", 5, false); // => 6
剩余參數只包含那些沒有對應形參的實參,而 arguments 對象包含了傳給函數的所有實參。
arguments 對象不是一個真實的數組,而剩余參數是真實的 Array實例。
所以,能夠在剩余參數上面直接使用所有的數組方法,比如 sort,map,forEach,pop。
而如果想在arguments對象上使用數組方法,你首先得將它轉換為真實的數組。
[].slice.call(arguments)
arguments 對象對象還有一些附加的屬性 (比如callee屬性)。
解構賦值let [first,...rest]=[1,2,3,4,5]; first //1 rest //[2,3,4,5]
// ES5 a = list[0], rest = list.slice(1) // ES6 [a, ...rest] = list
const [first, ...rest] = []; first // undefined rest // []
let { x, ...y } = { x: 1, a: 2, b: 3 }; x // 1 y // { a: 2, b: 3 }
// 淺拷貝 let obj = { a: { b: 1 } }; let { ...x } = obj; obj.a.b = 2; x.a.b // 2
// ...運算符的解構賦值不能繼承自原型對象的屬性 let o1 = { a: 1 }; let o2 = { b: 2 }; o2.__proto__ = o1; let { ...o3 } = o2; o3 // { b: 2 } o3.a // undefined
const o = Object.create({ x: 1, y: 2 }); o.z = 3; let { x, ...newObj } = o; let { y, z } = newObj; x // 1 y // undefined z // 3
上面代碼中,變量x是單純的解構賦值,所以可以讀取對象o繼承的屬性;變量y和z是擴展運算符的解構賦值,只能讀取對象o自身的屬性,所以變量z可以賦值成功,變量y取不到值。
ES6 規定,變量聲明語句之中,如果使用解構賦值,擴展運算符后面必須是一個變量名,而不能是一個解構賦值表達式,所以上面代碼引入了中間變量newObj,如果寫成下面這樣會報錯。
let { x, ...{ y, z } } = o; // SyntaxError: ... must be followed by an identifier in declaration contexts
注意:
解構賦值只能放在參數最后一位,否則會報錯。
解構賦值要求等號右邊是一個對象,如果等號右邊是undefined或null,就會報錯,因為它們無法轉為對象。
解構賦值的拷貝是淺拷貝,即如果一個鍵的值是復合類型的值(數組、對象、函數)、那么解構賦值拷貝的是這個值的引用,而不是這個值的副本
...運算符的解構賦值,不能復制繼承自原型對象的屬性
變量聲明語句之中,如果使用解構賦值,擴展運算符后面必須是一個變量名,而不能是一個解構賦值表達式
rest參數&解構賦值擴展某個函數的參數,引入其他操作。
function baseFunction({ a, b }) { // ... } function wrapperFunction({ x, y, ...restConfig }) { // 使用 x 和 y 參數進行操作 // 其余參數傳給原始函數 return baseFunction(restConfig); }展開語法
spread運算則可以看作是rest參數的逆運算。
數組展開數組作為參數序列、復制數組、合并數組、代替apply、...+表達式
1.展開數組作為函數參數(...arr), 可以將數組轉化為逗號分隔的參數序列
console.log(1,...arr) arr1.push(...arr);
注意:push方法的參數不能是數組
函數應用實例
JavaScript 的函數只能返回一個值,如果需要返回多個值,只能返回數組或對象。擴展運算符提供了解決這個問題的一種變通方法。
var dateFields = readDateFields(database); var d = new Date(...dateFields);
上面代碼從數據庫取出一行數據,通過擴展運算符,直接將其傳入構造函數Date。
2.復制數組
const a2 = a1.concat(); // ES5 const itemsCopy = [...items]; // ES6
注意:這兩種方法都是淺拷貝,使用的時候需要注意。
3.合并數組
// 合并生成一個新的數組,不影響原來的兩個數組 arr = [4].concat(list) // ES5 arr = [4, ...list] // ES6
// 擴展arr變量,追加arr2 Array.prototype.push.apply(arr, list); // ES5 arr.push(...list); // ES6
如果擴展運算符后面是一個空數組,則不產生任何效果
[...[], 1] // [1]
4.可以替代apply方法,apply要求將參數合并為數組,作為參數傳入
Function.apply(obj,args)方法能接收兩個參數
obj:這個對象將代替Function類里this對象
args:這個是數組,它將作為參數傳給Function(args-->arguments)
數組沒有max方法。Math.max.apply(null,[]);
Math.max.apply(null,[14,3,7]) // ES5寫法 Math.max(...[14,3,7]) // ES6寫法 // 等同于 Math.max(14, 3, 77);
5.擴展運算符后面還可以放置表達式。
const arr = [ ...(x > 0 ? ["a"] : []), "b", ];對象
復制對象、完整克隆、合并對象、...+表達式、取值函數get
1.拷貝
let z = { a: 3, b: 4 }; let n = { ...z }; // { a: 3, b: 4 }
這等同于使用Object.assign方法。
let aClone = { ...a }; // 等同于, let aClone = Object.assign({}, a);
上面的例子只是拷貝了對象實例的屬性。
2.完整克隆一個對象,拷貝實例屬性+對象原型的屬性
// 寫法一 const clone1 = { __proto__: Object.getPrototypeOf(obj), ...obj }; // 寫法二 const clone2 = Object.assign( Object.create(Object.getPrototypeOf(obj)), obj ); // 寫法三 const clone3 = Object.create( Object.getPrototypeOf(obj), Object.getOwnPropertyDescriptors(obj) )
上面代碼中,寫法一的__proto__屬性在非瀏覽器的環境不一定部署,因此推薦使用寫法二和寫法三。
3.合并對象
// 合并 let ab = { ...a, ...b }; // 等同于, let ab = Object.assign({}, a, b);
如果用戶自定義的屬性,放在擴展運算符后面,則擴展運算符內部的同名屬性會被覆蓋掉
let aWithOverrides = { ...a, x: 1, y: 2 }; // 等同于 let aWithOverrides = { ...a, ...{ x: 1, y: 2 } }; // 等同于 let x = 1, y = 2, aWithOverrides = { ...a, x, y }; // 等同于 let aWithOverrides = Object.assign({}, a, { x: 1, y: 2 });
上面代碼中,a對象的x屬性和y屬性,拷貝到新對象后會被覆蓋掉。這用來修改現有對象部分的屬性就很方便了
let newVersion = { ...previousVersion, name: "New Name" // Override the name property };
上面代碼中,newVersion對象自定義了name屬性,其他屬性全部復制自previousVersion對象。
如果把自定義屬性放在擴展運算符前面,就變成了設置新對象的默認屬性值。
let aWithDefaults = { x: 1, y: 2, ...a }; // 等同于 let aWithDefaults = Object.assign({}, { x: 1, y: 2 }, a); // 等同于 let aWithDefaults = Object.assign({ x: 1, y: 2 }, a);
如果擴展運算符后面是一個空對象,則沒有任何效果。
如果擴展運算符的參數是null或undefined,這兩個值會被忽略,不會報錯。
{...{}, a: 1} // { a: 1 } let emptyObject = { ...null, ...undefined }; // 不報錯
4.與數組的擴展運算符一樣,對象的擴展運算符后面可以跟表達式。
const obj = { ...(x > 1 ? {a: 1} : {}), b: 2, };
5.對象中取值函數get問題
擴展運算符的參數對象之中,如果有取值函數get,這個函數是會執行的
// 并不會拋出錯誤,因為 x 屬性只是被定義,但沒執行 let aWithXGetter = { ...a, get x() { throw new Error("not throw yet"); } }; // 會拋出錯誤,因為 x 屬性被執行了 let runtimeError = { ...a, ...{ get x() { throw new Error("throw now"); } } };字符串
[..."hello"] // [ "h", "e", "l", "l", "o" ]
Unicode 是有兩個字節、四字節之區分。上面的寫法,有一個重要的好處,那就是能夠正確識別四個字節的 Unicode 字符。
"xuD83DuDE80y" //"x
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98086.html
摘要:使用新特性開發微信小程序國際化與本地化新特性國際化與本地化新增了很多對于國際化的支持,比如時間格式,貨幣格式,數字格式等。 ECMAScript 6(簡稱ES6)是JavaScript語言的最新標準。因為當前版本的ES6是在2015年發布的,所以又稱ECMAScript 2015。 微信小程序支持絕大部分ES6的新增特性。 使用ES6新特性開發微信小程序(1) ES6新特性:Cons...
摘要:目前的標準化工作正在進行中,預計會在年月份放出正式敲定的版本。反的方法可以接收一個參數并且返回值取決與它的構造函數。之后就可以用這個返回值做為對象的鍵了。 本文基于lukehoban/es6features ,同時參考了大量博客資料,具體見文末引用。 ES6(ECMAScript 6)是即將到來的新版本JavaScript語言的標準,代號harmony(和諧之意,顯然沒有跟上我國的步伐...
摘要:的翻譯文檔由的維護很多人說,阮老師已經有一本關于的書了入門,覺得看看這本書就足夠了。前端的異步解決方案之和異步編程模式在前端開發過程中,顯得越來越重要。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。 JavaScript Promise 迷你書(中文版) 超詳細介紹promise的gitbook,看完再不會promise...... 本書的目的是以目前還在制定中的ECMASc...
摘要:但是,的本質仍然是函數,是構造函數的另外一種寫法。報錯原生構造函數的繼承對于一些原生的構造函數,比如,,,等,在是無法通過方法實現原生函數的內部屬性,原生函數內部的無法綁定,內部屬性獲得不了。 在沒有學習 ES6 之前,學習 React,真的是一件非常痛苦的事情。即使之前你對 ES5 有著很好的基礎,包括閉包、函數、原型鏈和繼承,但是 React 中已經普遍使用 ES6 的語法,包括 ...
閱讀 1369·2021-10-13 09:39
閱讀 1333·2021-09-23 11:22
閱讀 2243·2019-08-30 14:05
閱讀 1059·2019-08-29 17:03
閱讀 771·2019-08-29 16:24
閱讀 2227·2019-08-29 13:51
閱讀 656·2019-08-29 13:00
閱讀 1290·2019-08-29 11:24