#
Object
Object initializer
對象可以通過 new Object(), Object.create() 方法, 或者使用字面 標記 (初始化 標記)初始化。
對象初始化,由花括號{}包含的一個由0個或者多個對象屬性名和關聯值組成的列表構成。
#計算的屬性名
從ES6開始,對象初始化語法開始支持計算的屬性名。
其允許在[]中放入表達式,計算結果可以當做屬性名。
這種用法和用方括號訪問屬性非常類似,用來讀取和設置屬性。
現在同樣的語法也可以用於對象字面值
var i = 0; var a = { ["foo" + ++i]: i, ["foo" + ++i]: i, ["foo" + ++i]: i }; console.log(a.foo1); // 1 console.log(a.foo2); // 2 console.log(a.foo3); // 3 var param = 'size'; var config = { [param]: 12, ["mobile" + param.charAt(0).toUpperCase() + param.slice(1)]: 4 }; console.log(config); // { size: 12, mobileSize: 4 }
Object.setPrototypeOf()
Object.setPrototypeOf(obj, prototype)
將一個指定的對象的原型設置為另一個對象或者null(既對象的[[Prototype]]內部屬性).
如 果對象的[[Prototype]]被修改成不可擴展(通過 Object.isExtensible()查看),就會拋出 TypeError異常。如果prototype參數不是一個對象或者null(例如,數字,字符串,boolean,或者 undefined),則什么都不做。否則,該方法將obj的[[Prototype]]修改為新的值。
相對於 Object.prototype.__proto__ ,它被認為是修改對象原型更合適的方法
#添加原型鏈
通過Object.getPrototypeOf()和 Object.prototype.__proto__的組合,可以給一個新的原型對象添加完整的原型鏈
/** *** Object.appendChain(@object, @prototype) * * Appends the first non-native prototype of a chain to a new prototype. * Returns @object (if it was a primitive value it will transformed into an object). * *** Object.appendChain(@object [, "@arg_name_1", "@arg_name_2", "@arg_name_3", "..."], "@function_body") *** Object.appendChain(@object [, "@arg_name_1, @arg_name_2, @arg_name_3, ..."], "@function_body") * * Appends the first non-native prototype of a chain to the native Function.prototype object, then appends a * new Function(["@arg"(s)], "@function_body") to that chain. * Returns the function. * **/ Object.appendChain = function(oChain, oProto) { if (arguments.length < 2) { throw new TypeError('Object.appendChain - Not enough arguments'); } if (typeof oProto === 'number' || typeof oProto === 'boolean') { throw new TypeError('second argument to Object.appendChain must be an object or a string'); } var oNewProto = oProto, oReturn = o2nd = oLast = oChain instanceof this ? oChain : new oChain.constructor(oChain); for (var o1st = this.getPrototypeOf(o2nd); o1st !== Object.prototype && o1st !== Function.prototype; o1st = this.getPrototypeOf(o2nd) ) { o2nd = o1st; } if (oProto.constructor === String) { oNewProto = Function.prototype; oReturn = Function.apply(null, Array.prototype.slice.call(arguments, 1)); this.setPrototypeOf(oReturn, oLast); } this.setPrototypeOf(o2nd, oNewProto); return oReturn; }
#一:給一個原型添加鏈
function Mammal() {
this.isMammal = 'yes'; } function MammalSpecies(sMammalSpecies) { this.species = sMammalSpecies; } MammalSpecies.prototype = new Mammal(); MammalSpecies.prototype.constructor = MammalSpecies; var oCat = new MammalSpecies('Felis'); console.log(oCat.isMammal); // 'yes' function Animal() { this.breathing = 'yes'; } Object.appendChain(oCat, new Animal()); console.log(oCat.breathing); // 'yes'
#二:將一個基本類型轉化為對應的對象類型並添加到原型鏈上
function Symbol() {
this.isSymbol = 'yes'; } var nPrime = 17; console.log(typeof nPrime); // 'number' var oPrime = Object.appendChain(nPrime, new Symbol()); console.log(oPrime); // '17' console.log(oPrime.isSymbol); // 'yes' console.log(typeof oPrime); // 'object'
#三:給函數類型的對象添加一個鏈,並添加一個新的方法到那個鏈上
function Person(sName) {
this.identity = sName; } var george = Object.appendChain(new Person('George'), 'console.log("Hello guys!!");'); console.log(george.identity); // 'George' george(); // 'Hello guys!!'
Object.assign()
Object.assign(target, ...sources)
可以把任意多個的源對象所擁有的自身可枚舉屬性拷貝給目標對象,然后返回目標對象。
只會拷貝源對象自身的並且可枚舉的屬性到目標對象身上。
注意1,對於訪問器屬性,該方法會執行那個訪問器屬性的 getter 函數,然后把得到的值拷貝給目標對象,如果想拷貝訪問器屬性本身,使用 Object.getOwnPropertyDescriptor() 和 Object.defineProperties() 方法。
注意2,String類型和 Symbol 類型的屬性都會被拷貝。
注意3,在屬性拷貝過程中可能會產生異常,比如目標對象的某個只讀屬性和源對象的某個屬性同名,這時該方法會拋出一個 TypeError 異常,
拷貝過程中斷,已經拷貝成功的屬性不會受到影響,還未拷貝的屬性將不會再被拷貝。
注意4, Object.assign 會跳過那些值為 null 或 undefined 的源對象。
#克隆一個 object
var obj = { a: 1 }; var copy = Object.assign({}, obj); console.log(copy); // { a: 1 }
#合並 objects
var o1 = { a: 1 }; var o2 = { b: 2 }; var o3 = { c: 3 }; var obj = Object.assign(o1, o2, o3); console.log(obj); // { a: 1, b: 2, c: 3 } console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目標對象自身也會改變。
#拷貝 symbol 類型的屬性
var o1 = { a: 1 }; var o2 = { [Symbol("foo")]: 2 }; var obj = Object.assign({}, o1, o2); console.log(obj); // { a: 1, [Symbol("foo")]: 2 }
#繼承屬性和不可枚舉屬性是不能拷貝的
var obj = Object.create({foo: 1}, { // foo 是個繼承屬性。 bar: { value: 2 // bar 是個不可枚舉屬性。 }, baz: { value: 3, enumerable: true // baz 是個自身可枚舉屬性。 } }); var copy = Object.assign({}, obj); console.log(copy); // { baz: 3 }
#原始類型會被包裝為 object
var v1 = "abc"; var v2 = true; var v3 = 10; var v4 = Symbol("foo") var obj = Object.assign({}, v1, null, v2, undefined, v3, v4); // 原始類型會被包裝,null 和 undefined 會被忽略。 // 注意,只有字符串的包裝對象才可能有自身可枚舉屬性。 console.log(obj); // { "0": "a", "1": "b", "2": "c" }
#異常會打斷接下來的拷貝任務
var target = Object.defineProperty({}, "foo", { value: 1, writeable: false }); // target 的 foo 屬性是個只讀屬性。 Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4}); // TypeError: "foo" is read-only // 注意這個異常是在拷貝第二個源對象的第二個屬性時發生的。 console.log(target.bar); // 2,說明第一個源對象拷貝成功了。 console.log(target.foo2); // 3,說明第二個源對象的第一個屬性也拷貝成功了。 console.log(target.foo); // 1,只讀屬性不能被覆蓋,所以第二個源對象的第二個屬性拷貝失敗了。 console.log(target.foo3); // undefined,異常之后 assign 方法就退出了,第三個屬性是不會被拷貝到的。 console.log(target.baz); // undefined,第三個源對象更是不會被拷貝到的。
#拷貝訪問器(accessor)
var obj = { foo: 1, get bar() { return 2; } }; var copy = Object.assign({}, obj); console.log(copy); // { foo: 1, bar: 2 }, copy.bar的值來自obj.bar的getter函數的返回值 // 下面這個函數會拷貝所有自有屬性的屬性描述符 function completeAssign(target, ...sources) { sources.forEach(source => { let descriptors = Object.keys(source).reduce((descriptors, key) => { descriptors[key] = Object.getOwnPropertyDescriptor(source, key); return descriptors; }, {}); // Object.assign 默認也會拷貝可枚舉的Symbols Object.getOwnPropertySymbols(source).forEach(sym => { let descriptor = Object.getOwnPropertyDescriptor(source, sym); if (descriptor.enumerable) { descriptors[sym] = descriptor; } }); Object.defineProperties(target, descriptors); }); return target; } var copy = completeAssign({}, obj); console.log(copy); // { foo:1, get bar() { return 2 } }
Object.is()
Object.is(value1, value2);
用來判斷兩個值是否是同一個值。
Object.is() 會在下面這些情況下認為兩個值是相同的:
兩個值都是 undefined
兩個值都是 null
兩個值都是 true 或者都是 false
兩個值是由相同個數的字符按照相同的順序組成的字符串
兩個值指向同一個對象
兩個值都是數字並且
都是正零 +0
都是負零 -0
都是 NaN
都是除零和 NaN 外的其它同一個數字
這種相等性判斷邏輯和傳統的 == 運算符所用的不同,== 運算符會對它兩邊的操作數做隱式的類型轉換(如果它們是不同類型的值的話),
然后才進行相等性比較,(所以才會有類似 "" == false 為 true 的現象),但 Object.is 不會做這種類型轉換。
而且,即便嚴格相等運算符 === 不會對操作數進行類型轉換,但它不能區分兩個不同的數字 -0 和 +0,還會把兩個 NaN 看成是不相等的。
#
Object.is('foo', 'foo'); // true Object.is(window, window); // true Object.is('foo', 'bar'); // false Object.is([], []); // false var test = { a: 1 }; Object.is(test, test); // true Object.is(null, null); // true // 兩個特例,=== 也沒法判斷的情況 Object.is(0, -0); // false Object.is(NaN, 0/0); // true
#
string
String.raw()
String.raw(callSite, ...substitutions)
String.raw() 是一個模板字符串的標簽函數,
它的作用類似於 Python 中的字符串前綴 r 和 C# 中的字符串前綴 @,
是用來獲取一個模板字符串的原始字面量值的。
String.raw() 是唯一一個內置的模板字符串標簽函數。
#
console.log(String.raw `Hi\n!`); // "Hi\\n!",這里得到的不是 Hi 后面跟個換行符,而是跟着 \ 和 n 兩個字符 console.log(String.raw `Hi\u000A!`); // "Hi\\u000A!",同上,這里得到的會是 \、u、0、0、0、A 6個字符, // 任何類型的轉義形式都會失效,保留原樣輸出 let name = "Bob"; console.log(String.raw `Hi\n${name}!`); // "Hi\\nBob!",內插表達式還可以正常運行 console.log(String.raw({raw: "test"}, 0, 1, 2)); // "t0e1s2t",通常不需要把它當成普通函數來調用
#
array
Array.prototype.entries()
arr.entries()
entries() 方法返回一個 Array Iterator 對象,該對象包含數組中每一個索引的鍵值對。
#
var arr = ['a', 'b', 'c']; var eArr = arr.entries(); console.log(eArr.next().value); // [0, 'a'] console.log(eArr.next().value); // [1, 'b'] console.log(eArr.next().value); // [2, 'c'] //using a for…of loop: var arr = ['a', 'b', 'c']; var eArr = arr.entries(); for (let e of eArr) { console.log(e); }
#
Array.from()
Array.from(arrayLike[, mapFn[, thisArg]])
Array.from() 方法可以將一個類數組對象或可迭代對象轉換成真正的數組。
在 ES6 中, Class 語法允許為內置類型(比如 Array)和自定義類新建子類(比如叫 SubArray)。
這些子類也會繼承父類的靜態方法,比如 SubArray.from(),調用該方法后會返回子類 SubArray 的一個實例,而不是 Array 的實例。
#
// 將類數組對象(arguments)轉換成數組 (function () { var args = Array.from(arguments); console.log(args);// [1, 2, 3] return args; })(1, 2, 3); // 將可迭代對象(Set 對象)轉換成數組 console.log(Array.from(new Set(["foo", window]))); // ["foo", window] // Map 對象也可以 var m = new Map([[1, 2], [2, 4], [4, 8]]); console.log(Array.from(m)); // [[1, 2], [2, 4], [4, 8]] // 字符串對象既是類數組又是可迭代對象 console.log(Array.from("foo")); // ["f", "o", "o"] // 使用 map 函數轉換數組元素 console.log(Array.from([1, 2, 3], x => x + x)); // [2, 4, 6] // 生成一個數字序列 console.log(Array.from({length:5}, (v, k) => k)); // [0, 1, 2, 3, 4]
