1. 程式人生 > >es6 物件的擴充套件,物件的解構和深拷貝

es6 物件的擴充套件,物件的解構和深拷貝

物件的擴充套件

屬性的簡潔表示法

ES6 允許直接寫入變數和函式,作為物件的屬性和方法。這樣的書寫更加簡潔。

const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}

// 等同於
const baz = {foo: foo};

方法也可以簡寫。

const o = {
  method() {
    return "Hello!";
  }
};

// 等同於

const o = {
  method: function() {
    return "Hello!";
  }
};

屬性名錶達式

JavaScript 定義物件的屬性,有兩種方法。

// 方法一
obj.foo = true;

// 方法二
obj['a' + 'bc'] = 123;

但是,如果使用字面量方式定義物件(使用大括號),在 ES5 中只能使用方法一(識別符號)定義屬性。

var obj = {
  foo: true,
  abc: 123
};

ES6 允許字面量定義物件時,用方法二(表示式)作為物件的屬性名,即把表示式放在方括號內。

let propKey = 'foo';

let obj = {
  [propKey]: true,//等價於 foo:true
  ['a' + 'bc']: 123
};

表示式還可以用於定義方法名。

let obj = {
  ['h' + 'ello']() {
    return 'hi';
  }
};

obj.hello() // hi

注意,屬性名錶達式與簡潔表示法,不能同時使用,會報錯。

// 報錯
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };

// 正確
const foo = 'bar';
const baz = { [foo]: 'abc'};

Object.is()

ES5 比較兩個值是否相等,只有兩個運算子:相等運算子(==)和嚴格相等運算子(===)。它們都有缺點,前者會自動轉換資料型別,後者的NaN

不等於自身(NaN是S5裡面在”===”符號下唯一一個自己都不等於自己的型別),以及+0等於-0。JavaScript 缺乏一種運算,在所有環境中,只要兩個值是一樣的,它們就應該相等。

ES6 提出同值相等演算法,用來解決這個問題。Object.is就是部署這個演算法的新方法。它用來比較兩個值是否嚴格相等,與嚴格比較運算子(===)的行為基本一致。

Object.is('foo', 'foo')
// true
Object.is({}, {})
// false

不同之處只有兩個:一是+0不等於-0,二是NaN等於自身。

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

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

Object.assign()

Object.assign方法用於物件的合併,將源物件(source)的所有可列舉屬性,複製到目標物件(target),順序就是引數順序。

const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

如果只有一個引數,Object.assign會直接返回該引數。

const obj = {a: 1};
Object.assign(obj) === obj // true

由於undefinednull無法轉成物件,所以如果它們作為引數,就會報錯。

Object.assign(undefined) // 報錯
Object.assign(null) // 報錯

注意:Object.assign可以用來處理陣列,但是會把陣列視為物件。

Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
//把陣列視為屬性名為 0、1、2 的物件,因此源陣列的 0 號屬性4覆蓋了目標陣列的 0 號屬性1。

Object.keys()

ES5 引入了Object.keys方法,返回一個數組,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵名。

var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]

ES2017 引入了跟Object.keys配套的Object.valuesObject.entries,作為遍歷一個物件的補充手段,供for...of迴圈使用。

let {keys, values, entries} = Object;
let obj = { a: 1, b: 2, c: 3 };

for (let key of keys(obj)) {
  console.log(key); // 'a', 'b', 'c'
}

for (let value of values(obj)) {
  console.log(value); // 1, 2, 3
}

for (let [key, value] of entries(obj)) {
  console.log([key, value]); // ['a', 1], ['b', 2], ['c', 3]
}

Object.values()

Object.values方法返回一個數組,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值。

const obj = { foo: 'bar', baz: 42 };
Object.values(obj)
// ["bar", 42]

返回陣列的成員順序,

const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]

上面程式碼中,屬性名為數值的屬性,是按照數值大小,從小到大遍歷的,因此返回的順序是bca

Object.entries

Object.entries方法返回一個數組,成員是引數物件自身的(不含繼承的)所有可遍歷(enumerable)屬性的鍵值對陣列。

const obj = { foo: 'bar', baz: 42 };
Object.entries(obj)
// [ ["foo", "bar"], ["baz", 42] ]

除了返回值不一樣,該方法的行為與Object.values基本一致。

物件的擴充套件運算子

解構賦值

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x // 1
y // 2
z // { a: 3, b: 4 }

由於解構賦值要求等號右邊是一個物件,所以如果等號右邊是undefinednull,就會報錯,因為它們無法轉為物件。

let { x, y, ...z } = null; // 執行時錯誤
let { x, y, ...z } = undefined; // 執行時錯誤

解構賦值必須是最後一個引數,否則會報錯。

let { ...x, y, z } = obj; // 句法錯誤
let { x, ...y, ...z } = obj; // 句法錯誤

注意,解構賦值的拷貝是淺拷貝,即如果一個鍵的值是複合型別的值(陣列、物件、函式)、那麼解構賦值拷貝的是這個值的引用,而不是這個值的副本。

let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2

擴充套件運算子

擴充套件運算子(...)用於取出引數物件的所有可遍歷屬性,拷貝到當前物件之中。

let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }

這等同於使用Object.assign方法。

let aClone = { ...a };
// 等同於
let aClone = Object.assign({}, a);

物件的深拷貝

  • 物件的深拷貝呢就是:當物件裡存在陣列或者其他物件作為屬性時,通過某些方法將內部的陣列或物件進行展開的操作!
//{a:1,b:2,{c:3,d:4}}
var deepCopy = function ( obj , deep ) {
    var o = obj instanceof Array?[]:{};
    for(var k in obj ) {
        var val = obj[k];

        if(deep && typeof val === "object" ){
            o[k] = deepCopy(val,deep);
        }else{
            o[k] = val;
        }
    }
    return o;
}