概览
对象属性的简洁表示法
ES6 容许间接写入变量和函数作为对象的属性和办法。
ES6 容许在对象中只写属性名,不写属性值。
let foo = 'bar';
let baz = {foo};
console.log(baz); // {foo:'bar'}
// same as
let baz1 = {foo:foo}
console.log(baz1); // {foo:'bar'}
let first = 'Jone';
let last = 'Doe';
let obj = {first,last};
console.log(obj); // {first: "Jone", last: "Doe"}
// same as
let obj1 = {first:first,last:last};
console.log(obj1); // {first: "Jone", last: "Doe"}
const HELLO = {method(){return 'hello'}
}
console.log(HELLO.method()); // 'hello'
// same as
const HELLO1 = {method:function(){return 'hello'}
}
console.log(HELLO1.method()); // 'hello'
理论使用中的一些例子:
// 用于人物名称及行为的对象
let birth = '2000/01/01'
const PERSON = {
name: '张三',
birth, // same as: birth:birth
hello() {console.log('我的名字是', this.name);}
// same as: hello:function(){...}
}
// 用于函数返回值
function getPoint(x = 1, y=10){return {x, y}
}
console.log(getPoint()); // {x: 1, y: 10}
console.log(getPoint(3,3)); // {x: 3, y: 3}
console.log(getPoint(3)); // {x: 3, y: 10}
// CommonJS 模块输入变量
let ms = {};
function getItem(key){return key in ms? ms[key] : null;
}
function setItem(key,value){ms[key] = value;
}
function clear(){ms = {};
}
module.exports = {getItem,setItem,clear};
// same as: module.exports = {getItem:getItem,setItem:setItem,clear:clear};
// 属性的赋值器和取值器
const CART = {
_wheels: 4,
get wheels(){return this._wheels;},
set wheels(value){if(value<this._wheels){throw new Error('数值太小了');
}
this._wheels = value;
}
}
属性名表达式
ES6 容许字面量定义对象时,用表达式作为对象的属性名,即把表达式放在方括号内。
定义对象属性的两种办法:
-
通过固定名称
let obj = {}; obj.foo = true; console.log(obj); // {foo: true}
-
通过表达式
let obj1 = {}; obj1['a'+'bc'] = 123; console.log(obj1); // {abc: 123}
let propKey = 'foo';
let propKeyObj = {[propKey]: true,
['a'+ 'bc']: 123
}
console.log(propKeyObj); // {foo: true, abc: 123}
let lastWord = 'last word';
let a = {
'first word':'hello',
[lastWord]:'world'
}
console.log(a); // {first word: "hello", last word: "world"}
console.log(a['first word']);// 'hello'
console.log(a[lastWord]); // 'world'
console.log(a['last word']); // 'world'
// 定义方法名
let methodName = {['h'+'ello'](){return 'hi'}
}
console.log(methodName.hello()); // 'hi'
留神:属性名表达式不能和简洁表达式同时应用
// 报错
let foo = 'bar';
let bar = 'abc';
let baz = {[foo]};
留神:属性表达式如果是一个对象,默认状况下会把对象转为字符串[object Object]
const keyA = {a:1};
const keyB = {b:2};
const myObject = {[keyA]: 'valueA',
[keyB]: 'valueB',
}
console.log(myObject); // {[object Object]: "valueB"}
Object.is(value1,value2)
与严格相等运算符(===)的行为基本一致;
解决严格运算符(===)NaN
不等于本身,以及 + 0 等于 - 0 的问题。
console.log(Object.is('foo','foo'));; // true
console.log({} === {}); // false
console.log(Object.is({},{})); // false
console.log(NaN === NaN); // false
console.log(Object.is(NaN,NaN)); // true
console.log(+0 === -0); // true
console.log(Object.is(+0,-0)); // false
console.log([0,NaN,2].indexOf(NaN)); // -1
console.log([0,NaN,2].findIndex(x => Object.is(x, NaN))); // 1
Object.assign(target,source_1,source_2,...)
Object.assign()
办法将源对象(source)所有可枚举的属性合并到指标对象(target)中: 它批改 target,首先将 source_1 的所有可枚举的本人的属性复制到 target 中,而后将 source_2 的所有本人的属性复制到 target 中,以此类推。最初,它返回 target。
let target = {a:1};
let source_1 = {b:2};
let source_2 = {c:3};
Object.assign(target,source_1,source_2);
console.log(target,source_1,source_2); // {a: 1, b: 2, c: 3} {b: 2} {c: 3}
让咱们更认真看看 Object.assign()
是如何运作的:
-
两种类型的属性键:同时反对
String
、Symbel
作为属性键;let v1 = 'abc'; let v2 = true; let v3 = 10; let v4 = {[Symbol('c')]: 'c'}; const obj = Object.assign({}, v1, v2, v3, v4); console.log(obj); // {0: "a", 1: "b", 2: "c", Symbol(c): "c"}
-
仅复制源对象可枚举的本身属性:不复制继承属性,也不复制不可枚举的属性;
const obj = Object.assign({b: 'c'}, Object.defineProperty({}, 'invisible',{ enumerable:false, // enumerable 属性称为‘可枚举性’value:'hello' }) ) console.log(obj); // {b: "c"}
-
通过赋值复制:指标对象中的属性是通过赋值 (外部操作[[Put]]) 创立的。这意味着,如果
target
领有 (本人的或继承的)setter
,则在复制期间将调用这些setter
。另一种办法是定义新的属性,这是一种总是创立新的本人的属性且从不调用setter
的操作。最后有人倡议应用Object.assign()
的一个变体,它应用定义而不是赋值的形式。这个提议在 ECMAScript 6 中曾经被回绝了,然而在当前的版本中可能会被重新考虑。let obj1 = {a: {b: 1}}; let obj2 = Object.assign({}, obj1); console.log(obj2); // {a: {b: 1}}
// Object.assign()办法履行的是浅复制,而不是深复制。
let target = {a: { b: ‘c’, d: ‘e’}};
let source = {a: { b: ‘hello’}};
const obj = Object.assign(target, source);
console.log(obj); // a: {b: “hello”}
console.log(target); // a: {b: “hello”}
常见用处:** 为对象增加属性 **
class Point{
constructor(x, y){
Object.assign(this, {x, y});
}
}
** 为对象增加办法 **
function SomeClass(){
}
Object.assign(SomeClass.prototype, {
someMethod(arg1,arg2){
// ...
},
anotherMethod(){
// ...
}
})
console.dir(SomeClass);
// same as
SomeClass.prototype.someMethod = function(arg1, arg2){
//…
};
SomeClass.prototype.anotherMethod = function(){
//…
}
** 克隆对象 **
// 克隆原始对象本身的值
function clone1(origin){
return Object.assign({}, origin);
}
// 克隆原始对象继承的值(放弃继承链)
function clone2(params) {
let paramsProto = Object.getPrototypeOf(params);
return Object.assigin(Object.create(paramsProto), params)
}
** 合并多个对象 **
// 多个对象合并到 target
const merge1 = (target, …sources) => Object.assign(target, …sources);
// 多对象合并返回新对象
const merge2 = (…sources) => Object.assign({}, …sources);
** 为属性指定默认值 **
const DEFAULTS = {
logLevel: 0,
output: ‘html’
};
function processContent(options){
options = Object.assign({},DEFAULTS,options);
console.log(options);
}
processContent(‘abc’); // {0: “a”, 1: “b”, 2: “c”, logLevel: 0, output: “html”}
processContent({‘abc’:’abc’}); // {logLevel: 0, output: “html”, abc: “abc”}
### 属性的遍历
> `for...in`、`Object.keys(obj)`、`Object.getOwnPropertyNames(obj)`、`Object.getOwnPropertySymbels(obj)`、`Reflect.ownKeys(obj)`
function allObj(){
this.name = ‘ 张三 ’; // 自有属性
this.age = ’12’; // 自有属性
this.invisible = {
enumerable: false,
value: 'hello'
},
this.invisible = {
enumerable: false,
value: 'hello'
}
}
allObj.prototype.disEnum = {
enumerable: false,
value: ‘disEnum’
}
allObj.prototype.Enum = {
enumerable: true,
value: ‘Enum’
}
let obj = new allObj
Object.assign(obj, {
a: ‘1’,
b: ‘2’,
c: ‘3’,
})
// let obj2 = Object.assign(obj1,
// Object.defineProperty({},)
// )
Object.assign(obj,
Object.defineProperty({}, ‘visible’,{
enumerable: true,
value: 'word'
})
)
console.log(obj); // allObj {a: “1”,age: “12”,b: “2”,c: “3”,invisible: {enumerable: false,value: ‘hello’},name: “ 张三 ”,visible: “word”,Symbol(c): “c”,__proto__:Enum: {enumerable: true, value: “Enum”},disEnum: {enumerable: false, value: “disEnum”}}
// for…in 循环遍历对象本身的和继承的属性(不含 Symbol 属性)
for(let key in obj){
console.log(key);
// name
// age
// invisible
// a
// b
// c
// invisible
// visible
// disEnum
// Enum
}
// Object.keys()返回一个数组,包含对象本身 (不含继承的) 的所有属性(不含 Symbol 属性)
console.log(Object.keys(obj)); // [“name”, “age”, “invisible”, “a”, “b”, “c”, “visible”]
// Object.getOwnPropertyNames 返回一个数组,蕴含对象本身的所有属性(不含 Symbol 属性,然而包含不可枚举属性)
console.log(Object.getOwnPropertyNames(obj)); // [“name”, “age”, “invisible”, “a”, “b”, “c”, “visible”]
// Object.getOwnPropertySymbols() 返回一个数组,蕴含所有对象本身的所有 Symbol 属性
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(c)]
// Reflect.ownKeys()返回一个数组,蕴含对象本身的所有属性,不论属性名是 Symbol 还是字符串,也不论是否可枚举
console.log(Reflect.ownKeys(obj)); // [“name”, “age”, “invisible”, “a”, “b”, “c”, “visible”, Symbol(c)]