2019年养成记录笔记的习惯,好好学习前端知识
vue的双向数据绑定,const实现原理,很多知识点都和Object的这个方法紧密相关,所以查看了MDN API 文档,记录学习
介绍
Object.defineProperty()是Object的静态方法,作用是可以给对象定义新属性,或修改已经存在的属性,并返回该对象。
可以直接在Object构造函数上调用此方法,而不是在Object类型的实例上调用此方法。
复制代码
语法
Object.defineProperty(obj, prop, descriptor)
参数: 1. obj: 需要定义或修改属性的对象自身
2. prop: 需要定义或者修改属性的名称
3. descriptor: 属性所拥有的一些特性
返回值: 被修改了属性或新增属性的对象自身
复制代码
描述
desciptor: 给对象的属性添加特性描述,目前提供两种形式:数据描述和访问器描述(getter-setter)。
描述符必须是这两种风格之一,不能两者兼而有之,下面会分别介绍
数据描述和访问器描述都是对象,他们存在共同的可选属性:
1. configurable: 目标属性是否可被删除或者可再次修改特性 true | false (default: false)
2. enumerable: 目标属性是否可以被枚举。true | false,也就是是否可以用 for····in,或 Object.keys()获取,(default: false)
数据描述符才存在的可选属性:
1. value: 属性对应的值,可以使任意类型的值.(default: undefined)
2. writable: 是否可以使用赋值运算符更改属性的值 true | false (default: false)
访问器描述才存在的可选属性:
1. get: 属性getter的函数(default: undefined), 是一种获取属性值的方法
2. set: 属性setter的函数(default: undefined), 是一种设置属性值的方法
note: 直接在对象上定义的属性,writable, configurable, enumerable默认值为true。eg
var o = {};
0.name = "test";
name的上面上个描述如为true;这就是点操作符和用Object.defineProperty()的不同
复制代码
使用
新增属性
当对象中不存在指定的属性时,Object.defineProperty()将按照描述创建新属性。
eg: //使用数据描述新增属性
var o = {}; // Creates a new object
Object.defineProperty(o, 'a', {
value: 37,
writable: true,
enumerable: true,
configurable: true
});
//'a' 属性就存在了o对象上,并且值为37
如果用访问器描述新增属性,则:
var bValue = 38;
Object.defineProperty(o, 'b', {
get() { return bValue; },
set(newValue) { bValue = newValue; },
enumerable: true,
configurable: true
});
o.b;//38;
复制代码
修改属性
writable属性(false代表属性值不可以更改)
var o = {}; // Creates a new object
Object.defineProperty(o, 'a', {
value: 37,
writable: false
});
console.log(o.a); // 37
o.a = 25; // 不会抛出错误,但是也并不会生效
// (在严格模式下会抛出错误,即使赋值是和以前一样的也会抛出错误)
console.log(o.a); // logs 37.
// strict mode
(function() {
'use strict'; //使用严格模式
var o = {};
Object.defineProperty(o, 'b', {
value: 2,
writable: false
});
o.b = 3; // throws TypeError: "b" is read-only 直接报错了
}());
复制代码
Enumerable 属性(Object.assign()或spread运算符是否选择该属性,for····in循环和Object.keys()是否可以获取该属性)
var o = {};
Object.defineProperty(o, 'a', {
value: 1,
enumerable: true
});
Object.defineProperty(o, 'b', {
value: 2,
enumerable: false
});
Object.defineProperty(o, 'c', {
value: 3
}); // enumerable defaults to false,默认是false
o.d = 4;//enumerable defaults to true ,上面有提到过,直接在对象上定义属性,这几个描述符属性默认值为true
// Symbol是ES6引入的一种新的原始数据类型,表示独一无二的值。后面我会好好学习
Object.defineProperty(o, Symbol.for('e'), {
value: 5,
enumerable: true
});
Object.defineProperty(o, Symbol.for('f'), {
value: 6,
enumerable: false
});
for (var i in o) {
console.log(i);
}
Object.keys(o); // ['a', 'd']
//logs 'a' and 'd', 所以用Symbol定义的属性,无论enumerable设置的是false还是true,for···in都循环不出来
o.propertyIsEnumerable('a'); // true
o.propertyIsEnumerable('b'); // false
o.propertyIsEnumerable('c'); // false
o.propertyIsEnumerable('d'); // true
o.propertyIsEnumerable(Symbol.for('e')); // true
o.propertyIsEnumerable(Symbol.for('f')); // false
复制代码
Configurable 属性(控制是否可以从对象中删除属性以及是否可以再次更改属性的特性)
var o = {};
Object.defineProperty(o, 'a', {
get() { return 1; },
configurable: false
});
Object.defineProperty(o, 'a', {
configurable: true
}); // Uncaught TypeError: Cannot redefine property: a
Object.defineProperty(o, 'a', {
enumerable: true
}); // Uncaught TypeError: Cannot redefine property: a
复制代码
getter and setter
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get() {
console.log('get!');
return temperature;
},
set(value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function() { return archive; };
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
//所以可以劫持setter和getter做很多事情,so const这些的原理应该知道了
复制代码
思考定义在原型上的属性
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
复制代码
function myclass() {
}
Object.defineProperty(myclass.prototype, "x", {
get() {
return this.stored_x;
},
set(x) {
this.stored_x = x;
}
});
var a = new myclass();
var b = new myclass();
a.x = 1;
console.log(b.x); // undefined
复制代码