深入了解Object.defineProperty

  原来写文章都是一次写两三个小时写完,偶尔看到一个人的博客了解到还有草稿箱这个功能,所以以后写文章的时候就舒服多了哈哈,可以存起来再发,不需要一口气写完了

  最近一直在看JavaScript高级程序设计,看到defineProperty的时候感受挺深的,因为大名鼎鼎的Vue的双向数据绑定的原理就是根据这个东西来的,所以看到这里的时候长了见识

  要说起Object.defineProperty的话,需要先来介绍一下JavaScript中的对象。

JavaScript中的对象

  面向对象的语言有一个标志,那就是他们都有类的概念,而通过类可以创建任意多个具有相同属性和方法的对象。ECMAScript中没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。

  JavaScript中的对象定义: 无序属性的集合,其属性可以包含基本值、对象或者函数。严格来讲,这就相当于说对象是一组没有特定顺序的值。对象的每个属性或方法都有一个名字,而每个名字都映射到一个值。正因为这样,可以把对象想象成散列表,就是一个键值对,其中的值可以是任意的(数据,函数,对象,数组~~)

  前面balabala一堆概念,真心感觉如果可以理解挺重要的 

 

创建对象

  可以使用构造函数,创建一个Object的实例,然后为其添加属性和方法

person.sayName();

   这个例子创建了一个名为person的对象,并为其添加了三个属性(name、age、和job)和一个方法(sayName),其中sayName()方法用于显示this.name 这个会被解析为person.name和值。

  不过现在创建这种对象大都是通过字面量的方式来创建了

person.sayName();

 这种写法的结果和上面的那一种是一样的,这种写法如果你要拓展功能的话就不能再赋值了,也是用到了上面的写法

这个样子去拓展它。

 

属性类型

    ES5定义只有内部采用的特性时,描述了属性的各种特征。定义这些特性时为了实现JavaScript引擎用的,因此在JavaScript中不能直接访问它们。为了表示特征是内部值,该规范把它们放在了两对儿方括号中,例如[[Enumerable]]

    前面例子中的name,age,job,home,showHome都是属性,引号后面的东西是值,说一下属性的一些东西。

    ECMAScript中有两种属性: 数据属性和访问器属性

数据属性

  数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性。

  [[Configurable]] 表示能否通过delete删除属性从而重新定义属性,能够通过属性的特性,或者能否把属性修改为访问器属性,像前面的例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。

  [[Enumerable]] 表示能否通过for-in循环返回属性。像前面例子中那样直接在对象上定义的属性,他们的这个特性默认值为true

  [[Writable]] 表示能够修改属性的值。像前面例子中那样直接在对象上定义的属性,他们的这个特性默认值为true 

  [[Value]] 包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为undefined

例子

for(var key in person){
console.log(key);
}
// 他这个属性的value值就是他在上面所定义的那一些,对这个值的任何修改都反映在这个位置
console.log(person.name);

person.name = 'goudan';
// 在这里也可以修改,因为[[Writable]]属性默认为true
console.log(person.name);

// [[Configurable]] 这个东西为true 表示也可以删除它
delete person.name;
console.log(person.name); // undefined 因为删除之后这个属性就不存在了 [[Value]]特性的默认值为undefined

 重点来了

Object.defineProperty()

  如果要修改 属性默认的特性 就必要要使用ES5的Object。defineProperty()方法。这个方法接收三个参数。

  属性所在的对象、 属性的名字、 一个描述符对象 (其中描述符对象的属性必须是: configurable、enumerable、writeable、和value)设置其中一个或多个值,可以修改对应的特性值

  下面去演示这些例子了,希望你也可以试着去尝试一遍,我举得例子写法可能比较啰嗦,希望没有尝试过的可以试着练习一下

  提示:我后面 // 注释后面的东西 是输出打印的东西,如有错误可以自己具体情况分析一下

writable的情况演示

  

enumerable的情况演示

for(var key in person){
console.log(key); // name,baba,job
}
// 三个属性都可以正常的打印出来
// 配置一下 enumerable
Object.defineProperty(person,'baba',{
enumerable: false
});

for(var key1 in person){
console.log(key1); // name job
}
// ??? baba去哪了? 我告诉你去哪了 因为配置了 enumerable: false
console.log(person.baba); // 1 不会影响输出

  

Configurable 的演示

Object.defineProperty(person,'name',{
configurable: false
});

console.log(person.name); // zhang
console.log(person.age); // 12

delete person.name;
console.log(person.name); // zhang
// 刚才删除不是undefined吗 configurable: false就不允许删除了
// 如果声明是严格模式的话 那一句 delete person.name 还会报错
person.name = 'wang'
console.log(person.name); // wang

注意:这个配置有一点需要注意一下

) // 这个东西一旦被配置为 false,以后在也不可以把他变为true了 会报错

 

Value的演示

当然了上面的属性只是单独演示的,这四个属性可以结合起来使用,比如我要定义一个永远都无法改变它的值

console.log(person.name); // wang
// 卧槽你个小兔崽子又改姓了 给我改回来
person.name = 'zhang';
console.log(person.name); // wang
// 你会发现 有些事情发生了就是发生了,永远也回不来了
person.name = 'zhang1';
console.log(person.name); // wang

  注意 在调用 Object.defineProperty()方法时,如果不指定,configurable、enumerable和writable特性的默认值都是true。

  你给我演示这一堆东西到底有啥意思,能干啥。我想告诉你可能都没有必要利用Object.defineProperty()方法提供的这些高级功能。不过,理解这些概念对理解JavaScript对象却非常有用

 

访问器属性

  访问器属性不包含数据值;他们包含一对儿getter和setter函数(不过这两个函数都不是必须的)在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性有如下4个特性  

[[Configurable]] : 能否修改属性的特性,或者能否把属性修改为数据属性。像前面的例子中那样直接在对象上定义的属性,它们的这个特性默认值为true

[[Enumerable]] : 能否通过for-in循环 *********和上面的一样
[[Get]]: 在读取属性的时候调用。 默认值 undefined
[[Set]]: 在写入属性的时候调用 默认值 undefined

前面两个属性大同小异,几乎是一样的,同样的访问器属性不能直接定义,必须使用Object.defineProperty()来定义.

get和set的演示,

  这个重要

Object.defineProperty(book,'year',{
get: function () {
console.log(获取的时候触发函数); // 每次获取的时候都会触发这个函数
console.log(this === book); // true 这里面的this就是book的引用 也就是book对象
return this._year;
},set: function (newValue) {
console.log('修改值的时候触发函数');
// newValue ----- 这里的newValue就是你设置的修改后的值
if(newValue> 2018){
this._year = newValue;
this.edition = newValue - 2018;
}
}
});

console.log(book.year);
// 2018 他的值也就是我们返回的值 book._year
// 如果get函数不写返回值就是undefined

book.year = 2020; // 修改值的时候触发函数
console.log(book); // {_year: 2019,edition: 2};

  vue双向数据绑定就是这个,当我们在修改数据的时候,会触发set那个函数,就在set函数中执行我们的逻辑,去修改数据,以后我会写一个大概的双向数据绑定的那个代码,会发出来,网上也有好多类似的代码。

上面的代码创建了一个book对象,并给他定义两个默认的属性: _year和edition。

  而访问器属性year则包含一个getter函数和一个setter函数。 getter函数返回_year的值,setter函数修改了_year和edition。这是使用访问器属性的常见方式,即设置一个属性的值会导致其他属性发生变化。

  不一定非要同时制定getter和setter。只指定getter意味着属性是不能写,尝试写入属性会被忽略。在严格模式下,尝试写入至指定了getter函数的属性会抛出错误。类似的,只指定setter函数的属性也不能读,否则在非严格模式下回返回undefined,而在严格模式下会抛出错误。

 

  同时定义多个属性的写法由于未对象定义多个属性的可能性很大,ES5又定义了一个Object.defineProperties()方法利用这个方法可以通过描述符一次定义多个属性。

  这个方法接收两个对象参数:第一个对象是哟啊添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应。

同时定义多个属性的写法

Object.defineProperties(book,{
_year: {
value: 2018
},edition: {
value: 1
},year: {
get: function () {
return this._year;
},set: function (newValue) {
console.log('修改函数触发触发了吗');
if(newValue>2018){
this._year = newValue;
this.edition += newValue - 2018;
}
}
}
});

console.log(book.year);

book.year = 2020;
console.log(book); //{_year: 2018,edition: 1}
// ???? 我前面不是触发了修改的函数了吗为什么没有改呢 上一个分开写的都修改成功了

  

别着急,下面来看一个新的API

Object.getOwnPropertyDescriptor()  

  读取属性的特性

使用Es5的Object.getOwnPropertyDescription() 方法,可以取得给定属性描述符。这个方法接收两个参数: 属性所在的对象和要读取其描述符的属性名称。返回值是一个对象,如果是访问器属性,这个对象的属性有 configurable enumerable writable 和value

  在JavaScript中,可以针对任何对象------包括DOM和BOM对象,使用Object.getOwnPropertyDescriptor()方法。

  如果你阅读了本文章有了一些收获,我会感到非常开心,由于能力有限,文章有的部分解释的不到位,希望在以后的日子里能慢慢提高自己能力,如果不足之处,还望指正。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


这篇文章主要介绍“基于nodejs的ssh2怎么实现自动化部署”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“基于nodejs...
本文小编为大家详细介绍“nodejs怎么实现目录不存在自动创建”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs怎么实现目录不存在自动创建”文章能帮助大...
这篇“如何把nodejs数据传到前端”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这...
本文小编为大家详细介绍“nodejs如何实现定时删除文件”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs如何实现定时删除文件”文章能帮助大家解决疑惑...
这篇文章主要讲解了“nodejs安装模块卡住不动怎么解决”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来...
今天小编给大家分享一下如何检测nodejs有没有安装成功的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文...
本篇内容主要讲解“怎么安装Node.js的旧版本”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎...
这篇“node中的Express框架怎么安装使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家...
这篇文章主要介绍“nodejs如何实现搜索引擎”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“nodejs如何实现搜索引擎...
这篇文章主要介绍“nodejs中间层如何设置”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“nodejs中间层如何设置”文...
这篇文章主要介绍“nodejs多线程怎么实现”,在日常操作中,相信很多人在nodejs多线程怎么实现问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法...
这篇文章主要讲解了“nodejs怎么分布式”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“nodejs怎么分布式”...
本篇内容介绍了“nodejs字符串怎么转换为数组”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情...
这篇文章主要介绍了nodejs如何运行在php服务器的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇nodejs如何运行在php服务器文章都...
本篇内容主要讲解“nodejs单线程如何处理事件”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“nodejs单线程如何...
这篇文章主要介绍“nodejs怎么安装ws模块”,在日常操作中,相信很多人在nodejs怎么安装ws模块问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法...
本篇内容介绍了“怎么打包nodejs代码”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!
本文小编为大家详细介绍“nodejs接收到的汉字乱码怎么解决”,内容详细,步骤清晰,细节处理妥当,希望这篇“nodejs接收到的汉字乱码怎么解决”文章能帮助大家解...
这篇“nodejs怎么同步删除文件”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇...
今天小编给大家分享一下nodejs怎么设置淘宝镜像的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希