对象中包含一系列属性,这些属性是无序的。每个属性都有一个字符串key和对应的value。(无序,key为字符串)
1、对象结构
拥有[[proto]]、[[class]](属于哪个类)、[[extensible]](是否允许添加新的属性)、writable、enumerable、configurable、value、get/set
2、new/原型链
1 | function foo() {} |
解析:
var obj = new foo();
obj的[[proto]]则会指向foo.prototype, 而foo的prototype则会指向Object.prototype,Object.prototype则会指向nullfoo.prototype.z = 3;
在foo.prototype添加一个属性zobj.z
会先从obj查找是否有z这个属性,然后再查找obj的[[proto]],即foo.prototypeobj.toString
该方法是在Object.prototype中,即Object.prototype.toString();
1 | obj.z = 5; |
解析:
obj.z = 5;
赋值不会因为obj没有z属性而继续往prototype找是否有这个属性,从而修改prototype的属性,什么意思呢?就是obj没有z属性,则只会在obj添加新的z属性,反而foo.prototype.z的值不会被修改。obj.hasOwnProperty("z"); foo.prototype.z; obj.z;
z的属性是添加到obj上的,foo.prototype.z是不会受到影响的,依旧保留。obj.z = undefined; obj.z; foo.prototype.z;
同理delete obj.z; obj.z; delete obj.z; obj.z;
delete 删除的只是obj的属性,而不会影响foo.prototype的属性,但当obj的z被删除后,obj.z查找步骤又跟之前一样会到foo.prototype原型链去查找。
3、Object.create
1 | var obj = Object.create({x: 1}); |
解析:
var obj = Object.create({x:1});
利用Object.create,则会创建一个新的对象,其原型链则指向参数。即obj -> {x:1} -> Object.prototype -> null
obj.x; // 1
调用原型链上的参数
4、属性操作
4.1 属性读写
1 | var obj = {x:1}; |
4.2 异常
1 | var obj = {x:1}; |
4.3 删除
1 | delete Object.prototype; // false, 这是因为Object.prototype的configurable为false |
总结:
是无法删除基本类型的,例如:
var a = 1; delete a; // false
是无法删除函数声明的,例如:
function func(){}; delete func; // false
可以删除隐式的全局变量,例如:
a = 1; window.a; // 1 delete a; //true
可以删除eval定义变量,例如:
eval("var x = 1"); delete x; //true
4.4 检测
"x" in obj;
不仅仅会在该对象找,还会沿原型链上找obj.hasOwnProperty("x")
只会在该对象找,不会到沿原型链上找obj.propertyIsEnumeratable
是否可枚举Object.defineProperty(obj, propertyName, propertyArgsObject);
1 | Object.defineProperty(obj, "x", {enumeratable: false, value: 1000}); |
5、getter/setter
用法:
1 | var obj = { |
栗子:
1 | function foo(){} |
解析:
Object.defineProperty(foo.prototype, "z", {get: function(){return 1;}});
给foo的原型链创建属性z,并给其属性声明get方法obj.z
调用原型链zobj.z = 10
由于原型链有getter方法,表明该属性在原型链上只读不可写,同时也不会给原型链上创建新属性obj.z
依旧调用原型链getter方法Object.defineProperty(obj, "z", {value: 100, configurable: true});
在obj上创建新属性z,并设置configurable为true,值为100obj.z // 100
调用obj本身的属性zdelete obj.z
因为configurable为true,因此可以删除obj.z
obj上的z被删除了,所以会重新从原型链上查找z属性
1 | var o = {}; |
解析: 没啥解释
6、属性标签
1 | // Object.getOwnPropertyDescriptor(obj, propertyName); |
解析:
-Object.keys(person)
获取该对象所有可枚举的属性
Object.getOwnPropertyDescriptor(obj, propertyName)
获取对象描述器,第一个参数是获取描述的对象,第二个参数是该对象的属性,若不存在则返回undefined,反之则返回该对象的属性配置Object.defineProperty(person, "name", {configurable: false, writable: false, enumerable: true, value: "Test"})
定义属性的配置,第一个参数是对象,第二个属性是不存在于该对象的属性,第三个则定义该对象的属性描述器对象
c(configurable)/w(writable) | c:true/w:true | c:true/w:false | c:false/w:true | c:false/w:false |
---|---|---|---|---|
修改属性的值 | √ | √ | √ | × |
通过属性赋值、修改属性的值 | √ | × | √ | × |
delete该属性返回true | √ | √ | × | × |
修改getter/setter方法 | √ | √ | × | × |
修改属性标签(除了writable从true修改为false总是允许) | √ | √ | × | × |
注意:假如我们想改属性的值,configurable与writable为false的话就没办法修改了,但是假如writable为false,而configurable为true的话,我们可以变相的通过configurable修改属性的值,如Object.defineProperty(xxx, x, {value: 1})或者通过configurable来修改属性的writable的值使其能被修改,如Object.defineProperty(xxx, x, {writable: true});
7、对象标签
对象标签有三种:[[proto]]、[[class]]、[[extensible]]
[[proto]]: 原型对象
[[class]]: 表明该对象是哪种类型的类
[[extensible]]: 对象是否能再被添加新的属性,如AS的dynamic
1 | var obj = {x: 1, y: 2}; |
解析:
Object.preventExtensions(obj)
阻止obj扩展新属性,但是不会影响到旧的属性Object.seal(obj)
设置configurable为falseObject.freeze(obj)
设置configurable跟writable为false
注意:以上的方法只会限制当前对象,并不会影响到原型链对象,若想影响原型链的对象,就得对原型链对象做同样的操作
8、序列化
8.1
1 | var obj = {x: 1, y: true, z: [1, 2, 3], nullVal: null}; |
总结:
JSON.stringify(obj);
序列化JSON.parse("{'x': 1}")
反序列化,注意属性是以””引起来undefined 的属性不会被序列化出来
NaN或Infinity 则会被序列化成null
new Date() 则会序列化成UTC时间格式
8.2 自定义
1 | var obj = { |
总结:自定义z属性,其中toJSON为固定写法,若不是toJSON则为"{"x":1,"y":2,"z":{"o1":1,"o2":2}}"