Object.preventExtensions(obj) 让一个对象变的不可扩展,也就是永远不能再添加新的属性。
Object.isExtensible(obj) 判断一个对象是否是可扩展的
Object.seal(obj)让一个对象密封(只能读写 不能新增)
Object.isSealed(obj)判断一个对象是否密封
Object.isFrozen(arr) 让一个对象被冻结(只能读)
Object.isFrozen(obj):判断一个对象是否被冻结
Object.keys(obj) 返回一个由给定对象的所有可枚举自身属性的属性名组成的数组
Object.getOwnPropertyNames(obj):返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性)组成的数组
Object.is(value1, value2):判断两个值是否是同一个值。
Object.create(proto [, propertiesObject ]) 是E5中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不是一个子函数,可以传一个null,第二个参数是对象的属性描述符,这个参数是可选的。
Object.assign 把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。
Object.defineProperty() 定义单个对象属性或方法(可以设置读写可枚举)
Object.defineProperties() 定义多个对象属性或方法(可以设置读写可枚举)复制代码
js中对Object对象的一些常用操作总结
前言
我前面的文章,写过js中“类”与继承的一些文章。ES5我们可以通过 构造函数 或者 Object.create()等方式来模拟出js中的“类”,当然,对象呢是类的实例化,我们可以通过如下方式创建对象:
var haorooms ={};
或者
var haorooms = new Object()复制代码
今天主要总结一下Object的一些常用方法。
Object.assign()
1、可以用作对象的复制
var obj = { a: 1 };
var copy = Object.assign({}, obj);
console.log(copy); // { a: 1 }复制代码
2、可以用作对象的合并
var o1 = { a: 1 };
var o2 = { b: 2 };
var o3 = { c: 3 };
var obj = Object.assign(o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1, b: 2, c: 3 }, 注意目标对象自身也会改变。复制代码
上面我们看到,目标对象o1自身也发生了改变。假如我们不想让o1改变,我们可以把三个对象合并到一个空的对象中,操作如下:
var obj = Object.assign({},o1, o2, o3);
console.log(obj); // { a: 1, b: 2, c: 3 }
console.log(o1); // { a: 1 }复制代码
注意:以下几个地方可能copy或者合并不成功,经常在面试中出现!
1、继承属性和不可枚举属性是不能拷贝的
var obj = Object.create({foo: 1}, { // foo 是个继承属性。
bar: {
value: 2 // bar 是个不可枚举属性。
},
baz: {
value: 3,
enumerable: true // baz 是个自身可枚举属性。
}
});
var copy = Object.assign({}, obj);
console.log(copy); // { baz: 3 }复制代码
2、原始类型会被包装为 object
var v1 = "abc";
var v2 = true;
var v3 = 10;
var v4 = Symbol("foo")
var obj = Object.assign({}, v1, null, v2, undefined, v3, v4);
// 原始类型会被包装,null 和 undefined 会被忽略。
// 注意,只有字符串的包装对象才可能有自身可枚举属性。
console.log(obj); // { "0": "a", "1": "b", "2": "c" }复制代码
3、异常会打断接下来的拷贝任务
var target = Object.defineProperty({}, "foo", {
value: 1,
writable: false
}); // target 的 foo 属性是个只读属性。
Object.assign(target, {bar: 2}, {foo2: 3, foo: 3, foo3: 3}, {baz: 4});
// TypeError: "foo" is read-only
// 注意这个异常是在拷贝第二个源对象的第二个属性时发生的。
console.log(target.bar); // 2,说明第一个源对象拷贝成功了。
console.log(target.foo2); // 3,说明第二个源对象的第一个属性也拷贝成功了。
console.log(target.foo); // 1,只读属性不能被覆盖,所以第二个源对象的第二个属性拷贝失败了。
console.log(target.foo3); // undefined,异常之后 assign 方法就退出了,第三个属性是不会被拷贝到的。
console.log(target.baz); // undefined,第三个源对象更是不会被拷贝到的。复制代码
Object.create()
这个我之前就提到过了,可以模拟出js中的“类”。具体可以看:www.haorooms.com/post/js_lei…
注意!上文中我只应用了Object.create()的第一个参数,其实还有第二个参数!
Object.create(proto, [ propertiesObject ])复制代码
第二个参数是可选的,主要用于指定我们创建的对象的一些属性,(例如:是否可读、是否可写,是否可以枚举等等)可以通过下面案例来了解第二个参数!
var o;
o = Object.create(Object.prototype, {
// foo会成为所创建对象的数据属性
foo: { writable:true, configurable:true, value: "hello" },
// bar会成为所创建对象的访问器属性
bar: {
configurable: false,
get: function() { return 10 },
set: function(value) { console.log("Setting `o.bar` to", value) }
}})
// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
o = Object.create({}, { p: { value: 42 } })
// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
o.p = 24
o.p
//42
o.q = 12
for (var prop in o) {
console.log(prop)
}
//"q"
delete o.p
//false
//创建一个可写的,可枚举的,可配置的属性p
o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });复制代码
Object.is()
用来判断两个值是否是同一个值。
下面是一些例子,面试中可能会提及
Object.is('haorooms', 'haorooms'); // true
Object.is(window, window); // true
Object.is('foo', 'bar'); // false
Object.is([], []); // false
var test = { a: 1 };
Object.is(test, test); // true
Object.is(null, null); // true
// 特例
Object.is(0, -0); // false
Object.is(-0, -0); // true
Object.is(NaN, 0/0); // true复制代码
Object.keys()
这个方法会返回一个由给定对象的自身可枚举属性组成的数组,数组中属性名的排列顺序和使用 for...in 循环遍历该对象时返回的顺序一致 (两者的主要区别是 一个 for-in 循环还会枚举其原型链上的属性)。
例如:
/* 类数组对象 */
var obj = { 0 : "a", 1 : "b", 2 : "c"};
alert(Object.keys(obj));
// 弹出"0,1,2"
/* 具有随机键排序的数组类对象 */
var an_obj = { 100: 'a', 2: 'b', 7: 'c' };
console.log(Object.keys(an_obj));
// console: ['2', '7', '100']复制代码
常用其他操作
1、删除对象中的某个值,前面案例中也谢了可以直接用delete
delete o.p复制代码
2、对象循环,这个我之前单独写了一篇文章:www.haorooms.com/post/object…
3、对象或者数组赋值
js中对象和数组赋值,不和PHP等后端语言一样,只能赋值一层,例如:
var haorooms={};
//可以这么写
haorooms["前端博客"]="Haorooms,Aaron个人博客。记录本人工作中遇到的问题,以及经验总结和分享!";
//但是假如如下写就会报错!
haorooms["前端博客"]["des"]="Haorooms,Aaron个人博客。记录本人工作中遇到的问题,以及经验总结和分享!"
//Uncaught TypeError: Cannot set property 'des' of undefined复制代码
我们在循环多层赋值的时候可以这么写:
var haorooms={};
haorooms["前端博客"] = haorooms["前端博客"] || {};
haorooms["前端博客"]["des"]=haorooms["前端博客"]["des"] || "Haorooms,Aaron个人博客。记录本人工作中遇到的问题,以及经验总结和分享"复制代码
这样就可以多层赋值了!此方法同样可以应用在数组上面!
其他一些不是很常用的对象操作属性。如下:
1、Object.freeze() 方法可以冻结一个对象,冻结指的是不能向这个对象添加新的属性,不能修改其已有属性的值,不能删除已有属性,以及不能修改该对象已有属性的可枚举性、可配置性、可写性。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。
2、Object.isFrozen() 方法判断一个对象是否被冻结(frozen)。
3、Object.isExtensible() 方法判断一个对象是否是可扩展的(是否可以在它上面添加新的属性)。
4、Object.isSealed() 方法判断一个对象是否是密封的(sealed)。
5、Object.seal() 方法可以让一个对象密封,并返回被密封后的对象。密封对象是指那些不能添加新的属性,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性,但可能可以修改已有属性的值的对象。
虽然说现在并不是所有的浏览器都已经支持ECMAScript5的新特性,但相比于ECMAScript4而言ECMAScript5被广大浏览器厂商广泛接受,目前主流的浏览器中只有低版本的IE不支持,其它都或多或少的支持了ECMAScript5的新特性,其中重中之重自然是一切对象的基类型——Object
Object.create(prototype[,descriptors])
这个方法用于创建一个对象,并把其prototype属性赋值为第一个参数,同时可以设置多个descriptors,关于decriptor下一个方法就会介绍这里先不说。只需要这样就可以创建一个原型链干净对象了
var o = Object.create({
"say": function () {
alert(this.name);
},
"name":"Byron"
});复制代码
Object.defineProperty(O,Prop,descriptor) / Object.defineProperties(O,descriptors)
想明白这两个函数必须明白descriptor是什么,在之前的JavaScript中对象字段是对象属性,是一个键值对,而在ECMAScript5中引入property,property有几个特征
1. value:值,默认是undefined
2. writable:是否是只读property,默认是false,有点像C#中的const
3. enumerable:是否可以被枚举(for in),默认false
4. configurable:是否可以被删除,默认false
同样可以像C#、Java一样些get/set,不过这两个不能和value、writable同时使用
5.get:返回property的值得方法,默认是undefined
6.set:为property设置值的方法,默认是undefined
Object.defineProperty(o,'age', {
value: 24,
writable: true,
enumerable: true,
configurable: true
});
Object.defineProperty(o, 'sex', {
value: 'male',
writable: false,
enumerable: false,
configurable: false
});
console.log(o.age); //24
o.age = 25;
for (var obj in o) {
console.log(obj + ' : ' + o[obj]);
/*
age : 25 //没有把sex : male 遍历出来
say : function () {
alert(this.name);
}
name : Byron
*/
}
delete o.age;
console.log(o.age);//undefined
console.log(o.sex); //male
//o.sex = 'female'; //Cannot assign to read only property 'sex' of #
delete o.age;
console.log(o.sex); //male ,并没有被删除复制代码
也可以使用defineProperties方法同时定义多个property,
Object.defineProperties(o, {
'age': {
value: 24,
writable: true,
enumerable: true,
configurable: true
},
'sex': {
value: 'male',
writable: false,
enumerable: false,
configurable: false
}
});复制代码
Object.getOwnPropertyDescriptor(O,property)
这个方法用于获取defineProperty方法设置的property 特性
var props = Object.getOwnPropertyDescriptor(o, 'age');
console.log(props); //Object {value: 24, writable: true, enumerable: true, configurable: true}复制代码
Object.getOwnPropertyNames
获取所有的属性名,不包括prototy中的属性,返回一个数组
console.log(Object.getOwnPropertyNames(o)); //["age", "sex"]复制代码
例子中可以看到prototype中的name属性没有获取到
Object.keys()
和getOwnPropertyNames方法类似,但是获取所有的可枚举的属性,返回一个数组
console.log(Object.keys(o)); //["age"]复制代码
上面例子可以看出不可枚举的sex都没有获取的到
Object.preventExtensions(O) / Object.isExtensible
方法用于锁住对象属性,使其不能够拓展,也就是不能增加新的属性,但是属性的值仍然可以更改,也可以把属性删除,Object.isExtensible用于判断对象是否可以被拓展
console.log(Object.isExtensible(o)); //true
o.lastName = 'Sun';
console.log(o.lastName); //Sun ,此时对象可以拓展
Object.preventExtensions(o);
console.log(Object.isExtensible(o)); //false
o.lastName = "ByronSun";
console.log(o.lastName); //ByronSun,属性值仍然可以修改
//delete o.lastName;
console.log(o.lastName); //undefined仍可删除属性
o.firstname = 'Byron'; //Can't add property firstname, object is not extensible 不能够添加属性复制代码
Object.seal(O) / Object.isSealed
方法用于把对象密封,也就是让对象既不可以拓展也不可以删除属性(把每个属性的configurable设为false),单数属性值仍然可以修改,Object.isSealed由于判断对象是否被密封
Object.seal(o);
o.age = 25; //仍然可以修改
delete o.age; //Cannot delete property 'age' of #复制代码
Object.freeze(O) / Object.isFrozen
终极神器,完全冻结对象,在seal的基础上,属性值也不可以修改(每个属性的wirtable也被设为false)
Object.freeze(o);
o.age = 25; //Cannot assign to read only property 'age' of #复制代码
最后
上面的代码都是在Chrome 29下一严格模式(’use strict’)运行的,而且提到的方法都是Object的静态函数,也就是在使用的时候应该是Object.xxx(x),而不能以对象实例来调用。总体来说ES5添加的这些方法为javaScript面向对象设计提供了进一步的可配置性,用起来感觉很不错。