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); //{}