ES6-Object
# # ES6-Object
Object是js最重要的数据结构,es6对其进行了重大升级。除了解构 (opens new window) (opens new window)外,Object还提供了大量的基础方法。另外Object对象属性及其方法太常用,有些相似的方法容易使用错误,故根据MDN (opens new window) (opens new window)归类整理。注意文中重点标注的文字以及角标标注的ES发布版本。
# # 1. Key/Value
# # 1.1 Object.keys(obj)ES5
该方法返回一个给定对象的自身可枚举属性
组成的数组。
只列出自身的枚举属性(内部使用obj.hasOwnProperty(prop)指示对象自身属性中是否具有指定的属性)
Object.keys = (function() {
return function() {
var result = [];
for (var prop in obj) {
if (hasOwnProperty.call(obj, prop)) result.push(prop);
}
return result;
}
})()
2
3
4
5
6
7
8
9
10
11
# # 1.2 Object.values(obj)ES8
该方法返回一个给定对象自身的所有可枚举属性值
的数组。
只列出自身的枚举属性值
# # 1.3 Object.entries(obj)ES8
该方法返回一个给定对象自身可枚举属性的键值对
数组。
只列出自身枚举的键值对数组。
Object.fromEntries()Stage 3
是其逆方法,把键值对列表转换为一个对象.
# # 1.4 Object.getOwnPropertyNames(obj)
该方法返回一个数组,该数组对元素是 obj自身拥有的枚举或不可枚举属性
名称字符串。
自身的枚举和不枚举属性都会列出
# # 1.5 for ... in
for...in语句以任意顺序遍历一个对象的可枚举属性(包括原型链上的可枚举属性)
。包括原型链上的可枚举属性。
自身和原型链上的属性。
# # 2. Descriptor
# # 2.1 Object.defineProperty(obj, prop, descriptor)
该方法会直接在一个对象上定义一个
新属性,或者修改一个对象的现有属性, 并返回这个对象。
- descriptor
- configurable。 如果为false,则任何尝试删除目标属性或修改属性特性(writable, configurable, enumerable)的行为将被无效化。所以通常属性都有特性时,可以把configurable设置为true即可。
- writable 是否可写。设置成 false,则任何对该属性改写的操作都无效(但不会报错,严格模式下会报错),默认false。
- enumerable。是否能在for-in循环中遍历出来或在Object.keys中列举出来。
Reflect.defineProperty(target, propertyKey, attributes)
和以上Object.defineProperty类似,不过它返回一个Boolean值
Object.getOwnPropertyDescriptor()
返回对象对应的属性描述符。
# # 案例:
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
// throws an error in strict mode
console.log(object1.property1);
// expected output: 42
2
3
4
5
6
7
8
9
10
11
12
# # 实际应用
- 代理:
// old
//加入有一个目标节点, 我们想设置其位移时是这样的
var targetDom = document.getElementById('target');
var transformText = 'translateX(' + 10 + 'px)';
targetDom.style.webkitTransform = transformText;
targetDom.style.transform = transformText;
// new
Object.defineProperty(dom, 'translateX', {
set: function(value) {
var transformText = 'translateX(' + value + 'px)';
dom.style.webkitTransform = transformText;
dom.style.transform = transformText;
}
//这样再后面调用的时候, 十分简单
dom.translateX = 10;
dom.translateX = -10;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
- express获取属性时警告内容
[
'json',
'urlencoded',
'bodyParser',
'compress',
...
].forEach(function (name) {
Object.defineProperty(exports, name, {
get: function () {
throw new Error('Most middleware (like ' + name + ') is no longer bundled with Express and must be installed separately.');
},
configurable: true
});
});
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# # 2.2 Object.defineProperties(obj, props)
该方法直接在一个对象上定义一个或多个
新的属性或修改现有属性,并返回该对象。
Object.getOwnPropertyDescriptors()ES8
返回对象所有属性描述符。该方法引入目的是为了解决Object.assign()无法正确拷贝get属性和set属性的问题,详见此 (opens new window) (opens new window)
# # 3. Other
# # 3.1 Object.create(proto, [props])
根据已有的对象作为原型,创建新的对象。
// Object.create polyfill
Object.create = function(proto) {
function F() {
F.prototype = proto
}
return new F()
}
2
3
4
5
6
7
8
# # 举例:
const person = {
isHuman: false,
printIntroduction: function () {
console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`);
}
};
const me = Object.create(person);
me.name = "Matthew"; // "name" is a property set on "me", but not on "person"
me.isHuman = true; // inherited properties can be overwritten
me.printIntroduction();
const myObject = Object.create(null)
2
3
4
5
6
7
8
9
10
11
12
13
14
# # 思考题:为什么要有Object.create(null)?
Object.create(null)创建一个对象,但这个对象的原型链为null,即Fn.prototype = null
let a = null
let b = Object.create(null) // 返回纯{}对象,无prototype
let c = {}
let d = Object.create({})
a.attr // throw error
a.__proto__ // throw error
b // {}
b.attr // undefined
b.__proto__ // undefined
b.toString() // throw error
// d表现与c一致,毕竟只是多嵌套了一层原型链
c // { __proto__: {constructor: ƒ, ...} }
c.attr // undefined
c.__proto__ // {constructor: ƒ, ...}
c.toString() // "[object Object]"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
需要Object.create(null)的时候
:
- 需要一个非常干净且高度可定制的对象当作数据字典的时候
- 不考虑for in到原型链的属性(与Object.keys()等效)
所以绝大部分时候是直接使用{}
# # 3.2 Object.assign(target, ...sources)ES6
该方法用于将所有可枚举属性的值从一个或多个源对象复制
到目标对象。它将返回目标对象。(翻看源码能知道,它是一层浅拷贝)
# # 3.3 Object.is(value1, value2)ES6
该方法判断两个值是否是相同的值。
解决ES5中只有===和==判断的不足Equality comparisons and sameness (opens new window) (opens new window)
# # 3.4 Object.freeze(obj)Stage 1
该方法可以冻结
一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。该方法返回被冻结的对象。目前该方法在tc39 Stage1阶段,兼容性需要看后续发展。
Object.isFrozen(obj)判断一个对象是否被冻结
# # 3.5 对象的扩展
// 对象属性简写
const foo = 'bar';
const baz = {foo}; // 等价于{ foo: foo }
// 对象方法简写
const baz1 = {
func1() {}, // 等价于 func1: function() {}
foo
};
2
3
4
5
6
7
8
9
10