对象是无序属性的集合
建立自定义对象最简单的方式就是以字面量的形式建立对象(或建立一个Object实例),而后再为它添加属性和方法,以下所示:javascript
var person = { name: "Nicholas", age: 29, sayHi: function() { console.log(this.name); } }
可是咱们须要定义对象中的某个属性可否修改,可以重写等属性,那咱们应该如何定义html
Object.defineProperty()方法介绍(摘自MDN)前端
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象
语法:Object.defineProperty(obj, prop, descriptor)
参数:
(1)obj:须要被操做的目标对象
(2)prop:目标对象须要定义或修改的属性的名称
(3)descriptor:将被定义或修改的属性的描述符
返回:被传递给函数的对象java
是否能够删除目标属性或是否能够再次修改属性的特性(writable, configurable, enumerable)。默认为false框架
设置为true能够被删除或能够从新设置特性;
设置为false,不能被能够被删除或不能够从新设置特性,只能将writable
从true
置为false
dom
一旦把属性定义为不可配置的,就不能再把它便会可配置的,这一点很重要函数
主要起到数据的保护做用,决定了目标属性是否可使用delete删除,是否能够再次设置特性性能
//-----------------测试目标属性是否能被删除------------------------ var obj = {} // 第一种状况:configurable设置为true,能够被删除。 Object.defineProperty(obj, "newKey", { value: "hello", configurable: true }); // 删除属性 delete obj.newKey; console.log( obj.newKey ); //undefined // 第二种状况:configurable设置为false,不能被删除。 Object.defineProperty(obj, "newKey", { value: "hello", configurable: false }); // 删除属性 delete obj.newKey; console.log( obj.newKey ); //hello //-----------------测试是否能够再次修改特性------------------------ var obj = {} //第一种状况:configurable设置为false,不能再次修改特性。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: false, configurable: false }); //从新修改特性 Object.defineProperty(obj, "newKey", { value: "hello", writable: true, enumerable: true, configurable: true }); console.log( obj.newKey ); //报错:Uncaught TypeError: Cannot redefine property: newKey //第二种状况:configurable设置为true,能够再次修改特性。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: false, configurable: true }); //从新修改特性 Object.defineProperty(obj, "newKey", { value: "hello", writable: true, enumerable: true, configurable: true }); console.log( obj.newKey ); //hello
此属性是否能够被枚举(使用for...in或Object.keys())默认为false测试
设置为true能够被枚举;设置为false,不能被枚举this
var obj = {} // 第一种状况:enumerable设置为false,不能被枚举。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: false }); // 枚举对象的属性 for( var attr in obj ){ console.log( attr ); // undefined } // 第二种状况:enumerable设置为true,能够被枚举。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false, enumerable: true }); // 枚举对象的属性 for( var attr in obj ){ console.log( attr ); //newKey }
属性对应的值,能够是任意类型的值,默认为undefined;
var obj = {} // 第一种状况:不设置value属性 Object.defineProperty(obj, "key", {}); console.log( obj.key ); //undefined // 第二种状况:设置value属性 Object.defineProperty(obj, "key", { value: "hello" }); console.log( obj.key ); //hello // 同字面定义的数据值对应
属性的值是否能够被重写。默认为false
设置为true能够被重写;设置为false,不能被重写
var obj = {} // 第一种状况:writable设置为false,不能重写。 Object.defineProperty(obj, "newKey", { value: "hello", writable: false }); // 更改newKey的值 obj.newKey = "change value"; console.log( obj.newKey ); //hello // 第二种状况:writable设置为true,能够重写 Object.defineProperty(obj, "newKey", { value: "hello", writable: true }); // 更改newKey的值 obj.newKey = "change value"; console.log( obj.newKey ); //change value
在调用 Object.defineProperty 方法给对象添加属性时,若是不指定,configurable、enumerable、writable这些值都为默认的false
==> 使用 Object.getOwnPropertyDescriptor() 方法来查看对象的内置属性
var obj = {}; // 第一种状况:使用 Object.defineProperty() 定义属性 Object.defineProperty(obj, 'key', { value: "hello" }); Object.getOwnPropertyDescriptor(obj, 'key'); // {value: "hello", writable: false, enumerable: false, configurable: false} // 第二种状况:字面量方式 obj.key = "hello"; Object.getOwnPropertyDescriptor(obj, 'key'); // {value: "hello", writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor()方法介绍(摘自MDN)
Object.getOwnPropertyDescriptor() 方法返回指定对象上一个自有属性对应的属性描述符。(自有属性指的是直接赋予该对象的属性,不须要从原型链上进行查找的属性)
语法:Object.getOwnPropertyDescriptor(obj, prop)
参数:
(1)obj:须要被操做的目标对象
(2)prop:目标对象内属性名称(String类型)
返回:若是指定的属性存在于对象上,则返回其属性描述符对象(property descriptor),不然返回 undefined
参照数据属性中的configurable属性
参照数据属性中的enumerable属性
在读取属性是调用的函数,默认值为undefined
var obj = {}, value = "hello"; Object.defineProperty(obj, 'key', { get: function() { console.log("获取obj.key的值上下文"); return value; } }); console.log(obj.key); // "获取obj.key的值上下文" hello obj.key = "new value"; console.log(obj.key); // "获取obj.key的值上下文" hello
在写入属性时调用的函数,默认值为undefined
// 通常不会单独为属性设置set而不设置get var obj = {}, value = "hello"; Object.defineProperty(obj, 'key', { set: function(val) { console.log("设置obj.key的值上下文"); } }); obj.key = "new value"; // "获取obj.key的值上下文" console.log(obj.key); // undefined
不必定非要同时指定getter和setter。只指定getter意味着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入只指定getter函数的属性会抛出错误。相似的,只指定setter函数的属性也不能读,不然在非严格模式下会返回undefined,而在严格模式下会抛出错误。
var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, "year", { get: function() { return this._year; }, set: function(newValue) { if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } }); book.year = 2005; alert(book.edition); //2
使用访问器属性的常见方式,即设置一个属性的值会致使其余属性发生变化
给对象o定义新的属性b,而且定义属性b的get和set方法,当o.b的时候会调用b属性的get方法,给b属性赋值的时候,会调用set方法,这就是修改数据的时候,视图会自动更新的关键前端获取数据后,须要根据数据操做dom,视图变化后,须要修改很多代码,有没有方法将数据和dom操做隔离,看一个例子
<!-- 显示用户信息的html模版 --> <div> <p>你好,<span id='nickName'></span></p> <div id="introduce"></div> </div>
// 视图控制器 var userInfo = {}; Object.defineProperty(userInfo, "nickName", { get: function(){ return document.getElementById('nickName').innerHTML; }, set: function(nick){ document.getElementById('nickName').innerHTML = nick; } }); Object.defineProperty(userInfo, "introduce", { get: function(){ return document.getElementById('introduce').innerHTML; }, set: function(introduce){ document.getElementById('introduce').innerHTML = introduce; } }); // 数据 // todo 获取用户信息的代码 // .... userInfo.nickName = "xxx"; userInfo.introduce = "我是xxx,我来自云南,..."
访问器属性是实现MVVM框架的核心原理哦~
Object.defineProperties() 方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象
语法:Object.defineProperties(obj, props)
参数:
(1)obj:在其上定义或修改属性的对象
(2)props:要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有数据描述符和访问器描述符两种
返回:传递给函数的对象
var obj = {}; Object.defineProperties(obj, { 'property1': { value: true, writable: true }, 'property2': { value: 'Hello', writable: false } // etc. etc. });
参考:
Javascript中的Object.defineProperty
MDN Object.defineProperty
MDN Object.getOwnPropertyDescriptor