[ES6] 一些類型方法的擴展


#

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]

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM