对象
对象是由多个名/值对组成的无序的集合。对象中每个属性对应任意类型的值。
在JS中有一下几种方法为对象定义属性
var o = {};
o.name = "frank";
o['age'] = 18;
Object.defineProperty(o, "city", {
value: "上海"
});
属性定义方法.PNG
Object.defineProperty()
- MDN定义:
Object.defineProperty()
方法会直接在对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。 - 兼容性: IE8以下不可。
- 语法:
Object.defineProperty(obj,prop,descriptor)
obj: 要定义属性的对象
prop: 要定义或修改的属性名称或Symbol
descriptor:要定义或修改的属性描述符
返回值: 此对象,即第一个参数obj
-
给对象的属性添加特性描述,目前提供两种形式:数据描述符合存取描述符
描述符可拥有的键值.PNG
创建属性
如果对象中不存在指定的属性,Object.defineProperty()
会创建这个属性
一旦使用Object.defineProperty
给对象添加属性,那么如果不设置属性的特性,那么configurable、enumerable、writable
这些值都为默认的false
var o = {};
Object.defineProperty(o, "b", {
value: "37",
enumerable: true,
configurable: true,
writable: true
});
创建属性b.PNG
value属性
value
属性对应的值,可以使任意值,默认是undefined。
var o = {}
Object.defineProperty(o, 'a', {})
Object.defineProperty(o, 'b', {
value: 'lili'
})
console.log(o.a) //undefined
console.log(o.b) // lili
writable属性
writable
属性对应的值是布尔值,当为false
时,该属性被称为不可写,它不能被重新赋值
var o = {};
Object.defineProperty(o, "a", {
value: 37,
writable: false
});
o.a = 38; //没有错误被抛出
console.log(o.a); //37 a的值并未修改
enumerable属性
enumerable
属性定义了对象的属性是否可以在for...in
循环和Object.keys()
中被枚举。enumerable
的默认值为false,但是如果使用赋值方式o.a=1
,enumerable
的默认值是true。
var o = {};
Object.defineProperty(o, "a", {
value: 1,
enumerable: true
});
Object.defineProperty(o, "b", {
value: 2,
enumerable: false
});
Object.defineProperty(o, "c", {
value: 3
}); //此种方式默认为false
o.e = 4; //此种方式默认为true
for (let i in o) {
console.log(i); //a , e
}
console.log(Object.keys(o)); //[a,e]
configurable属性
configurable
属性作用:是否可以删除目标属性或是否可以再次修改属性的特性(writable, configurable, enumerable)。设置为true可以被删除或可以重新设置特性;设置为false,不能被可以被删除或不可以重新设置特性。默认为false。
var o = {};
Object.defineProperty(o, "a", {
get() {
return 1;
},
configurable: false
});
Object.defineProperty(o, "a", {
configurable: true
}); // throws a TypeError
Object.defineProperty(o, "a", {
enumerable: true
});
Object.defineProperties(o, "a", {
set() {}
});
console.log(o.a); // logs 1
delete o.a; // Nothing happens,并没有删除a
console.log(o.a); // logs 1
存取器描述:getter/setter
注意:当使用了getter或setter方法,不允许使用writable和value这两个属性
getter
是一种获得属性值的方法
setter
是一种设置属性值的方法。
var o = {};
var initValue = "hello";
Object.defineProperty(o, "name", {
get() {
return initValue;
},
set(value) {
initValue = value;
return initValue;
}
});
console.log(o.name); //hello
o.name = "lili";
console.log(o.name); //lili
get或set不是必须成对出现,任写其一就可以。如果不设置方法,则get和set的默认值为undefined
继承属性
- 如果访问者的是属性是被继承的,它的get和set方法会在子对象的属性被访问或者修改时被调用,如果这些方法用一个变量存执,该值会被所有对象共享
function myClass() {}
var value; //定义一个变量,存储属性值,但是会共用属性值
Object.defineProperty(myClass.prototype, "x", {
get() {
return value;
},
set(x) {
value = x;
}
});
var a = new myClass();
var b = new myClass();
a.x = 1;
console.log(b.x); //1
// a与b公用属性x
- 这可以通过将值存储在另一个属性中解决。在 get 和 set 方法中,this 指向某个被访问和修改属性的对象。
function myClass() {}
Object.defineProperty(myClass.prototype, "x", {
get() {
return this.stored_x;
},
set(x) {
stored_x = x;
}
});
var a = new myClass();
var b = new myClass();
a.x = 1;
console.log(b.x); //undefied
- 如果一个不可写的属性被继承,它仍然可以防止修改对象的属性。
function myclass() {}
myclass.prototype.x = 1;
Object.defineProperty(myclass.prototype, "y", {
writable: false,
value: 1
});
var a = new myclass();
a.x = 2;
console.log(a.x); // 2
console.log(myclass.prototype.x); // 1
a.y = 2; // Ignored, throws in strict mode
console.log(a.y); // 1
console.log(myclass.prototype.y); // 1
实际运用
- MVVM中数据‘双向绑定’实现
如vue,qjs等大部分mvvm框架(angular用的是脏处理)都是通过Object.defineProperty来实现数据绑定的。 - 优化对象获取和修改属性方式
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;
//甚至可以拓展设置如scale, originX, translateZ,等各个属性,达到下面的效果
dom.scale = 1.5; //放大1.5倍
dom.originX = 5; //设置中心点X
}
- 增加属性获取和修改时的信息
通过修改get属性方法,让用户调用废弃属性时抛错并带上自定义的错误信息。
[
xxxxx
].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. Please see https://github.com/senchalabs/connect#middleware.');
},
configurable: true
});
});
网友评论