-
10. Object.keys() Object.values() Object.entries()
-
keys() 返回一个数组,
成员是参数对象自身的(不含继承的)
所有可遍历(enumerable)属性的键名。
- var obj = { foo: 'bar', baz: 42 };
Object.keys(obj)
// ["foo", "baz"]
- 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]
}
-
values() 方法返回一个数组,成员是参数对象自身的
(不含继承的)所有可遍历(enumerable)属性的键值。
- const obj = { 100: 'a', 2: 'b', 7: 'c' };
Object.values(obj)
// ["b", "c", "a"]
- const obj = Object.create({}, {p: {value: 42}});
Object.values(obj) // []
- const obj = Object.create({}, {p:
{
value: 42,
enumerable: true
}
});
Object.values(obj) // [42]
-
entries()
方法返回一个数组,
成员是参数对象自身的(不含继承的)
所有可遍历(enumerable)属性的键值对数组。
- let obj = { one: 1, two: 2 };
for (let [k, v] of Object.entries(obj)) {
console.log(
`${JSON.stringify(k)}: ${JSON.stringify(v)}`
);
}
// "one": 1
// "two": 2
-
11. 对象的扩展运算符(...)
-
1 解构赋值
- const [a, ...b] = [1, 2, 3];
a // 1
b // [2, 3]
- let obj = { a: { b: 1 } };
let { ...x } = obj;
obj.a.b = 2;
x.a.b // 2
-
(2)扩展运算符
扩展运算符(...)用于取出参数对象的所有可遍历属性,
拷贝到当前对象之中。
- let z = { a: 3, b: 4 };
let n = { ...z };
n // { a: 3, b: 4 }
- let aClone = { ...a };
// 等同于
let aClone = Object.assign({}, a);
-
1. 属性的简介写法
- const foo = 'bar';
const baz = {foo};
baz // {foo: "bar"}
// 等同于
const baz = {foo: foo};
- function getPoint() {
const x = 1;
const y = 10;
return {x, y};
}
- 允许直接写入变量和函数,作为对象的属性和方法
-
2. 属性名表达式
-
方法一是直接用标识符作为属性名,
- // 方法一
obj.foo = true;
// 方法二
obj['a' + 'bc'] = 123;
-
方法二是用表达式作为属性名,这时要将表达式放在方括号之内。
- let propKey = 'foo';
let obj = {
[propKey]: true,
['a' + 'bc']: 123
};
-
允许把表达式放在括号内
- let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
-
表达式可以用于定义方法名
- 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 Object],这一点要特别小心
- const keyA = {a: 1};
const keyB = {b: 2};
const myObject = {
[keyA]: 'valueA',
[keyB]: 'valueB'
};
myObject // Object {[object Object]: "valueB"}
-
3. 方法的name属性
-
返回函数名 xxx.funcxx.name
- const person = {
sayName() {
console.log('hello!');
},
};
person.sayName.name // "sayName"
-
getter setter函数名取值方法 xxx.get.name
- const obj = {
get foo() {},
set foo(x) {}
};
obj.foo.name
// TypeError: Cannot read property 'name' of undefined
const descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
-
bind方法的name
- doSomething.bind().name // "bound doSomething"
-
function构造函数创造的函数 -返回anonymous
- (new Function()).name // "anonymous"
-
4. 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.defineProperty(Object, 'is', {
value: function(x, y) {
if (x === y) {
// 针对+0 不等于 -0的情况
return x !== 0 || 1 / x === 1 / y;
}
// 针对NaN的情况
return x !== x && y !== y;
},
configurable: true,
enumerable: false,
writable: true
});
-
5. Object.assign 对象合并
-
将源对象的所有可枚举属性,
复制到目标对象
- const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}
-
注意,如果目标对象与源对象有同名属性,
或多个源对象有同名属性,
则后面的属性会覆盖前面的属性。
- const target = { a: 1, b: 1 };
const source1 = { b: 2, c: 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
-
如果该参数不是对象,则会先转成对象
- typeof Object.assign(2) // "object"
-
由于undefined和null无法转成对象,
所以如果它们作为参数,就会报错
- Object.assign(undefined) // 报错
Object.assign(null) // 报错
-
如果undefined和null不在首参数,就不会报错
- let obj = {a: 1};
Object.assign(obj, undefined) === obj // true
Object.assign(obj, null) === obj // true
-
拷贝属性
- 只拷贝源对象的自身属性(不拷贝继承属性invisible),
也不拷贝不可枚举的属性(enumerable: false)
-
注意点
-
浅拷贝
- Object.assign属于浅拷贝,
即如果源对象某个属性的值是对象,
那么目标对象拷贝得到的是这个对象的引用。
- const obj1 = {a: {b: 1}};
const obj2 = Object.assign({}, obj1);
obj1.a.b = 2;
obj2.a.b // 2
-
同名属性的替换
- const target = { a: { b: 'c', d: 'e' } }
const source = { a: { b: 'hello' } }
Object.assign(target, source)
// { a: { b: 'hello' } }
-
数组的处理
- Object.assign([1, 2, 3], [4, 5])
// [4, 5, 3]
-
(4)取值函数的处理
- const source = {
get foo() { return 1 }
};
const target = {};
Object.assign(target, source)
// { foo: 1 }
-
常见用途
-
1. 为对象添加属性
- class Point {
constructor(x, y) {
Object.assign(this, {x, y});
}
}
-
(2)为对象添加方法
- Object.assign(SomeClass.prototype, {
someMethod(arg1, arg2) {
···
},
anotherMethod() {
···
}
});
// 等同于下面的写法
SomeClass.prototype.someMethod = function (arg1, arg2) {
···
};
SomeClass.prototype.anotherMethod = function () {
···
};
-
(3)克隆对象
- function clone(origin) {
return Object.assign({}, origin);
}
-
深度克隆,保持原型链方法
- function clone(origin) {
let originProto = Object.getPrototypeOf(origin);
return Object.assign(Object.create(originProto), origin);
}
-
(4)合并多个对象
- 返回旧的对象
const merge =
(target, ...sources) => Object.assign(target, ...sources);
- 返回新的对象
const merge =
(...sources) => Object.assign({}, ...sources);
-
(5)为属性指定默认值
- const DEFAULTS = {
logLevel: 0,
outputFormat: 'html'
};
function processContent(options) {
options = Object.assign({}, DEFAULTS, options);
console.log(options);
// ...
}
-
防止属性值被覆盖
- const DEFAULTS = {
url: {
host: 'example.com',
port: 7070
},
};
processContent({ url: {port: 8000} })
// {
// url: {port: 8000}
// }
-
6. 属性的可枚举性和遍历
-
可枚举性
- 枚举描述对象
Object.getOwnPropertyDescriptor
- enumerable 可枚举属性
-
四个操作会忽略枚举属性
- for...in
自身和继承可枚举
- Object.keys()
自身可枚举键名
- JSON.stringify()
对象自身可枚举
- Object.assign()
拷贝自身可枚举
-
可遍历
- (1) for...in
遍历自身和继承
- (2) Object.keys(obj)
遍历自身
- (3) Object.getOwnPropertyNames(obj)
遍历自身
- (4) Object.getOwnPropertySymbols
自身symbol
- (5)Reflect.ownKeys(obj)
返回自身所有属性包括symbol和不可枚举属性和普通
-
7. Object.getOwnPropertyDescriptors()
-
带了S, 返回对象所有自身属性
-
实现代码
- function getOwnPropertyDescriptors(obj) {
const result = {};
for (let key of Reflect.ownKeys(obj)) {
result[key] = Object.getOwnPropertyDescriptor(obj, key);
}
return result;
}
- 不带S 返回单个属性 Object.getOwnPropertyDescriptor(target,obj)
-
引入目的,解决Object.assign()无法正确拷贝get和set属性的问题
- const source = {
set foo(value) {
console.log(value);
}
};
const target2 = {};
Object.defineProperties(target2, Object.getOwnPropertyDescriptors(source));
Object.getOwnPropertyDescriptor(target2, 'foo')
// { get: undefined,
// set: [Function: foo],
// enumerable: true,
// configurable: true }
- 优化写法
const shallowMerge = (target, source) => Object.defineProperties(
target,
Object.getOwnPropertyDescriptors(source)
);
-
+create 将对象克隆到新对象(浅拷贝)
- const clone = Object.create(Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj));
// 或者
const shallowClone = (obj) => Object.create(
Object.getPrototypeOf(obj),
Object.getOwnPropertyDescriptors(obj)
);
-
8. __proto__属性
-
Object.setPrototypeOf()
-
用来设置一个对象的prototype对象,
返回参数对象本身
推荐使用
- // 格式
Object.setPrototypeOf(object, prototype)
// 用法
const o = Object.setPrototypeOf({}, null);
- let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);
proto.y = 20;
proto.z = 40;
obj.x // 10
obj.y // 20
obj.z // 40
-
如果第一个参数不是对象,
会自动转为对象,函数还是返回第一个对象,
转不了则报错
- Object.setPrototypeOf(undefined, {})
// TypeError: Object.setPrototypeOf called on null or undefined
Object.setPrototypeOf(null, {})
// TypeError: Object.setPrototypeOf called on null or undefined
- Object.setPrototypeOf(1, {}) === 1 // true
Object.setPrototypeOf('foo', {}) === 'foo' // true
Object.setPrototypeOf(true, {}) === true // true
-
Object.getPrototypeOf()
-
用于读取一个对象的原型对象。
- function Rectangle() {
// ...
}
const rec = new Rectangle();
Object.getPrototypeOf(rec) === Rectangle.prototype
// true
Object.setPrototypeOf(rec, Object.prototype);
Object.getPrototypeOf(rec) === Rectangle.prototype
// false
-
如果不是对象则会自动转为对象
- // 等同于 Object.getPrototypeOf(Number(1))
Object.getPrototypeOf(1)
// Number {[[PrimitiveValue]]: 0}
// 等同于 Object.getPrototypeOf(String('foo'))
Object.getPrototypeOf('foo')
// String {length: 0, [[PrimitiveValue]]: ""}
// 等同于 Object.getPrototypeOf(Boolean(true))
Object.getPrototypeOf(true)
// Boolean {[[PrimitiveValue]]: false}
Object.getPrototypeOf(1) === Number.prototype // true
Object.getPrototypeOf('foo') === String.prototype // true
Object.getPrototypeOf(true) === Boolean.prototype // true
-
__proto__
-
用来读取当前对象的prototype属性
- // es6 的写法
const obj = {
method: function() { ... }
};
obj.__proto__ = someOtherObj;
// es5 的写法
var obj = Object.create(someOtherObj);
obj.method = function() { ... };
-
9. SUPER关键字
-
指向当前对象的原型对象
- const proto = {
x: 'hello',
foo() {
console.log(this.x);
},
};
const obj = {
x: 'world',
foo() {
super.foo();
}
}
Object.setPrototypeOf(obj, proto);
obj.foo() // "world"
-
12. NULL 传导运算符
- const firstName = (message
&& message.body
&& message.body.user
&& message.body.user.firstName) || 'default';
-
四种写法
- obj?.prop // 读取对象属性
obj?.[expr] // 同上
func?.(...args) // 函数或对象方法的调用
new C?.(...args) // 构造函数的调用