Javascript零碎之基础二
kekobin opened this issue · comments
Object
Object常见静态方法总览:
(1)对象属性模型的相关方法
- Object.getOwnPropertyDescriptor():获取某个属性的描述对象。
- Object.defineProperty():通过描述对象,定义某个属性。
- Object.defineProperties():通过描述对象,定义多个属性。
(2)控制对象状态的方法
- Object.preventExtensions():防止对象扩展。
- Object.isExtensible():判断对象是否可扩展。
- Object.seal():禁止对象配置。
- Object.isSealed():判断一个对象是否可配置。
- Object.freeze():冻结一个对象。
- Object.isFrozen():判断一个对象是否被冻结。
(3)原型链相关方法
- Object.create():该方法可以指定原型对象和属性,返回一个新的对象。
- Object.getPrototypeOf():获取对象的Prototype对象。
Object.create(proto,[propertiesObject])
- proto:新创建对象的原型对象
- propertiesObject:可选。要添加到新对象的可枚举(新添加的属性是其自身的属性,而不是其原型链上的属性)的属性。
由上图可见,proto 为null、Object、Object.prototype时,使用Object.create创建新对象的结构都是不一样的。不同点在于"是否继承与Object"、"还是继承于Object.prototype"。
为什么vue中普遍使用 Object.create(null) 初始化新对象,而不是{}呢?
- 使用create(null)创建的对象,没有任何属性,即可以把它当作一个非常纯净的map来使用,可以自己定义hasOwnProperty、toString方法,而不必担心会将原型链上的同名方法覆盖掉。
- 可以节省hasOwnProperty带来的一丢丢性能损失并且可以偷懒少些一点代码。因为在我们使用for..in循环的时候会遍历对象原型链上的属性,使用create(null)就不必再对属性进行检查了,当然,我们也可以直接使用Object.keys[]。
Object.keys(),Object.getOwnPropertyNames()
对于一般的对象来说,Object.keys()和Object.getOwnPropertyNames()返回的结果是一样的。只有涉及不可枚举属性时,才会有不一样的结果。Object.keys方法只返回可枚举的属性,Object.getOwnPropertyNames方法还返回不可枚举的属性名。
var a = ['Hello', 'World'];
Object.keys(a) // ["0", "1"]
Object.getOwnPropertyNames(a) // ["0", "1", "length"]
属性描述对象
JavaScript 提供了一个内部数据结构,用来描述对象的属性,控制它的行为,比如该属性是否可写、可遍历等等。这个内部数据结构称为“属性描述对象”(attributes object)。每个属性都有自己对应的属性描述对象,保存该属性的一些元信息。
下面是属性描述对象的一个例子。
{
value: 123, // 默认为undefined
writable: false, // 默认为true
enumerable: true,
configurable: false,
get: undefined,
set: undefined
}
- enumerable: 表示该属性是否可遍历,默认为true。如果设为false,会使得某些操作(比如for...in循环、Object.keys())跳过该属性。
- configurable: 表示可配置性,默认为true。如果设为false,将阻止某些操作改写该属性,比如无法删除该属性,也不得改变该属性的属性描述对象(value属性除外)。也就是说,configurable属性控制了属性描述对象的可写性。
- get: 表示该属性的取值函数(getter),默认为undefined。
- set: 表示该属性的存值函数(setter),默认为undefined。
Object.getOwnPropertyDescriptor(obj, propertyName)
获取属性描述对象。它的第一个参数是一个对象,第二个参数是一个字符串,对应该对象的某个属性名。
而 Object.getOwnPropertyDescriptors(obj) 功能一样,只不过获取obj所有属性的描述。
注意,Object.getOwnPropertyDescriptor方法只能用于对象自身的属性,不能用于继承的属性。
Object.getOwnPropertyNames() 和 Object.keys()
前者返回参数对象自身的全部属性的属性名,不管该属性是否可遍历;后者只返回可遍历的属性。
Object.defineProperty(),Object.defineProperties()
- Object.defineProperty方法允许通过属性描述对象,定义或修改一个属性,然后返回修改后的对象,它的用法如下。
Object.defineProperty(object, propertyName, attributesObject)
var obj = Object.defineProperty({}, 'p', {
value: 123,
writable: false,
enumerable: true,
configurable: false
});
obj.p // 123
obj.p = 246;
obj.p // 123
- Object.defineProperties 定义或修改多个属性,然后返回修改后的对象
var obj = Object.defineProperties({}, {
p1: { value: 123, enumerable: true },
p2: { value: 'abc', enumerable: true },
p3: { get: function () { return this.p1 + this.p2 },
enumerable:true,
configurable:true
}
});
obj.p1 // 123
obj.p2 // "abc"
obj.p3 // "123abc"
注意,一旦定义了取值函数get(或存值函数set),就不能将writable属性设为true,或者同时定义value属性,否则会报错。
enumerable
如果一个属性的enumerable为false,下面三个操作不会取到该属性。
- for..in循环
- Object.keys方法
- JSON.stringify方法
因此,enumerable可以用来设置“秘密”属性。
var obj = {};
Object.defineProperty(obj, 'x', {
value: 123,
enumerable: false
});
obj.x // 123
for (var key in obj) {
console.log(key);
}
// undefined
Object.keys(obj) // []
JSON.stringify(obj) // "{}"
configurable
configurable(可配置性)返回一个布尔值,决定了是否可以修改属性描述对象。也就是说,configurable为false时,value、writable、enumerable和configurable都不能被修改了。也决定了目标属性是否可以被删除(delete)。
存取器
除了直接定义以外,属性还可以用存取器(accessor)定义。其中,存值函数称为setter,使用属性描述对象的set属性;取值函数称为getter,使用属性描述对象的get属性。
var obj = Object.defineProperty({}, 'p', {
get: function () {
return 'getter';
},
set: function (value) {
console.log('setter: ' + value);
}
});
obj.p // "getter"
obj.p = 123 // "setter: 123"
JavaScript 还提供了存取器的另一种写法:
var obj = {
get p() {
return 'getter';
},
set p(value) {
console.log('setter: ' + value);
}
};
存取器往往用于,属性的值依赖对象内部数据的场合。
对象的拷贝
var extend = function (to, from) {
for (var property in from) {
if (!from.hasOwnProperty(property)) continue;
Object.defineProperty(
to,
property,
Object.getOwnPropertyDescriptor(from, property)
);
}
return to;
}
extend({}, { get a(){ return 1 } })
// { get a(){ return 1 } })
控制对象状态
有时需要冻结对象的读写状态,防止对象被改变。JavaScript 提供了三种冻结方法,最弱的一种是Object.preventExtensions,其次是Object.seal,最强的是Object.freeze。
- Object.preventExtensions(): 可以使得一个对象无法再添加新的属性。
- Object.seal(): 使得一个对象既无法添加新属性,也无法删除旧属性。
Object.seal实质是把属性描述对象的configurable属性设为false,因此属性描述对象不再能改变了。
Object.seal只是禁止新增或删除属性,并不影响修改某个属性的值。
- Object.freeze():可以使得一个对象无法添加新属性、无法删除旧属性、也无法改变属性的值,使得这个对象实际上变成了常量。
- Object.isFrozen(): 用于检查一个对象是否使用了Object.freeze方法。
用途是,确认某个对象没有被冻结后,再对它的属性赋值。
if (!Object.isFrozen(obj)) {
obj.p = 'world';
}
Object.prototype.toString()
作用是返回一个对象的字符串形式,默认情况下返回类型字符串。常用语判断数据类型。
Object.prototype.toString.call(value)
封装方法:
var type = function (o){
var s = Object.prototype.toString.call(o);
return s.match(/\[object (.*?)\]/)[1].toLowerCase();
};
['Null',
'Undefined',
'Object',
'Array',
'String',
'Number',
'Boolean',
'Function',
'RegExp'
].forEach(function (t) {
type['is' + t] = function (o) {
return type(o) === t.toLowerCase();
};
});
type.isObject({}) // true
type.isNumber(NaN) // true
type.isRegExp(/abc/) // true
Array
reduce(),reduceRight()
reduce方法和reduceRight方法依次处理数组的每个成员,最终累计为一个值。它们的差别是,reduce是从左到右处理(从第一个成员到最后一个成员),reduceRight则是从右到左(从最后一个成员到第一个成员),其他完全一样。
a默认是数组的第一个元素,此时b为数组第二个元素。也可以像下面这样指定初始的a,则b初始是数组第一个元素:
JSON
JSON.stringify(obj, null, params)
第三个参数,用于增加返回的 JSON 字符串的可读性。如果是数字,表示每个属性前面添加的空格(最多不超过10个);如果是字符串(不超过10个字符),则该字符串会添加在每行前面。