var name = "Bob"; var getName = function(){console.log(this.name);}; var person = {name, getName}; //至關於 //var person = { //name: "Bob", //getName: function(){console.log(this.name);} //} person.getName(); //"Bob"
var o = { _age: 10, _score: 60, age(num){ if(num > 0) { this._age = num; return this; } return this._age; }, get score(){ return this._score; } }; console.log(o.age()); //10 o.age(15); console.log(o.age()); //15 console.log(o.score); //60 o.score = 100; //TypeError
注意,如下代碼是等同的:數組
var obj = { class () {} //並不會由於 class 是關鍵字而解析錯誤 }; //等價於 var obj = { 'class': function() {} };
若是一個方法是 Generator 函數,須要在前面加 *
:babel
var obj = { time: 1, *gen(){ yield "hello " + time; time++; } }
js 原本能夠這樣 obj['k'+'ey']
訪問一個對象屬性,如今也能夠這樣定義屬性了:函數
var key1 = "name"; var key2 = "age"; var o = { [key1]: "Bob", [key2]: 18, ['first' + key1]: "Ellen" }; o.name; //"Bob" o.age; //18 o.firstname; //"Ellen"
注意:該方法不能和上一小節使用已有標識符定義對象字面量的方法混合使用,不然會報錯;this
//錯誤用法 var foo = 'bar'; var bar = 'abc'; var baz = {[foo]}; //報錯
函數有 name 屬性,方法也就有 name 屬性。通常方法 name 返回函數名(不包括對象名),對於存取器方法,沒有 name 屬性:prototype
var o = { _age: 10, _score: 60, _name: "Bob", _firstname: "Ellen", set age(num){ if(num > 0) { this._age = num; return this; } }, get age(){ return this._age; }, get score(){ return this._score; }, name(n){ if(!n) return this._name + ' ' + this._firstname; this._name = n; return this; }, set firstname(n){ if(n) this._firstname = n; return this; } }; console.log(o.name.name); //"name" console.log(o.age.name); //undefined console.log(o.score.name); //undefined console.log(o.firstname); //undefined,因此 set 函數更不會有 name 屬性
若是對象的方法是個 symbol,name 屬性爲空字符串 ""
:rest
var sym1 = new Symbol("description of sym1"); var sym2 = new Symbol(); var o = { [sym1](){}, [sym2](){}, }; o[sym1].name; //"" o[sym2].name; //""
===
, 但有一點不同:-0 === +0; //true NaN === NaN; //false Object.is(-0, +0); //false Object.is(NaN, NaN); //true
var target = {a:1,b:2}; var source1 = {a:3,c:3}; var source2 = {a:2,d:0}; Object.assign(target, source1, source2); console.log(target); //{a: 2, b: 2, c: 3, d: 0}
對於屬性名是 symbol 的可枚舉屬性也會被複制:code
Object.assign({a:'b'}, {[Symbol('c')]:'d'}); //{a: "b", Symbol(c): "d"}
對於同名屬性存在嵌套對象,外層會被直接替換:對象
Object.assign({a:{b:'c',d:'e'}}, {a:{b:'hello'}}); //{a:{b:'hello'}}
能夠用 Object.assign處理數組,但會視其爲對象:排序
Object.assign([1,2,3], [4,5]); //[4, 5, 3]
技巧:爲對象添加屬性方法繼承
Object.assign(String.prototype, { newProperty: "value", newFunction: function(){} })
技巧:克隆對象
Object.assign({},origin);
技巧:爲對象添加屬性方法
Object.assign(target, ...source);
技巧:爲對象添加屬性方法
const DEFAULT_OPTION = { //默認值 a: 1, b: 2 }; function processContent(newOption){ return Object.assign({}, DEFAULT_OPTION, newOption); } //設置屬性應該是基本類型,不然會由於深拷貝出問題
如下6個操做會忽略不可枚舉的屬性
...
如下4個方法不忽略不可枚舉屬性
以上9個方法中,只有2個會操做包含繼承到的屬性
以上9個方法中,只有1個方法能夠得到 Symbol 屬性
除此以外須要強調的是 ES6 中,全部 class 的原型方法都是不可枚舉的:
Object.getOwnPropertyDescriptor(class{foo(){}}.prototype, foo).enumerable; //false
ES6 起,有了7中遍歷屬性的方法:
以上方法除了 for...of 之外,遍歷順序爲:
這是個很老很老的屬性,在你們想期待下,ES6終於把它寫進去了,嗯?...是寫進附錄了。這個屬性用來讀寫當前的對象的原型對象obj.constructor.prototype
從本質上來說,__proto__
是定義在Object.prototype
上的一個存取器函數:
function isObject(a){ return Object(a) === a; } Object.defineProperty(Object.prototype, '__proto__', { get(){ let _thisObj = Object(this); return Object.getPrototypeOf(_thisObj); }, set(proto){ if(this == null) throw new TypeError(); if(!isObject(this) || !isObject(proto)) return undefined; let status = Object.setPrototypeOf(this, proto); if(! status) throw new TypeError(); } });
可是,仍是不建議使用這個東西,畢竟看它這名字就是個內部屬性,由於它有了不加,但不保證因此終端都能用,因此ES6推薦用下面這兩個屬性:
Object.setPrototypeOf(obj, newProto); //寫 Object.getPrototypeOf(obj); //讀
簡單舉一個例子:
function Rectangle(){} var rec = new Rectangle(); Object.getPrototypeOf(rec) === Rectangle.prototype; //true Object.setPrototypeOf(rec, Object.prototype); Object.getPrototypeOf(rec) === Rectangle.prototype; //false
固然若是你把一個對象的原型設置成了 null, 也是能夠的,只是,它不具有任何你據說過的方法了:
var o = Object.setPrototypeOf({}, null); //等價於 var o = {'__proto__': null}; Object.getPrototypeOf(o); //null o.toString(); //TypeError: o.toString is not a function
這是 ES7 的一個提案, babel可使用器部分功能使用。
用法和數組中很相似,這裏再也不過多贅述,直接看幾個例子吧:
var {x,y,...z} = {x: 1, y: 2, a: 3, d: 4}; //x=1, y=2, z={a: 3, d: 4}
值得強調的是, 對象的rest參數形式執行的是淺拷貝,賦值獲得的是原對象的引用:
let obj = {a: {b: 1}}; let {...x} = obj; obj.a.b = 2; console.log(x.a.b); //2
此外 rest 不會複製不可枚舉屬性和繼承自原型的屬性:
var p = {a: 0}; var o = {b: 2}; var o = Object.defineProperty(o, "foo", { value: 2, configurable: true, enumerable: false, writable: true }); Object.setPrototypeOf(o, p); var u = { ...p }; console.log(u); //{b:2}
複製參數對象全部可遍歷屬性到當前對象中:
var o1 = {a: 1, b: 2}; var n = { ...o1 }; //n={a: 1, b: 2}; //至關於 var n = Object.assign({}, o1);
能夠用擴展運算符合並多個對象, 排後的屬性會覆蓋以前的屬性:
var source0 = {a:1,b:2}; var source1 = {a:3,c:3}; var source2 = {a:2,d:0}; Object.assign(target, source1, source2); var target = {...source0, ...source1, ...source2}; console.log(target); //{a: 2, b: 2, c: 3, d: 0}
注意一點:若是擴展運算符的參數對象有 get 方法,該方法會被執行:
var a = {o:1,p:2,m:4}; var withoutError = { ...a, get x(){ throw new Error(); } }; //不報錯 var withError = { ...a, ...{get x(){ throw new Error(); }} }; //報錯
若是擴展對象是 null 或 undefined,會被忽略,不報錯
var o = { ...null, ...undefined}; //不報錯 console.log(o); //{}