JS中setter/getter理解
JS中setter/getter理解
- JS对象属性
- get/set和getter/setter
- 数据属性
- Object.defineProperty()
- 访问器属性
- getter/setter创建及删除
- getter
- getter创建:
- getter删除:
- setter
- setter创建:
- setter删除:
- 应用
- Vue响应式原理
- 参考文章
JS对象属性
JS中对象包括属性和方法,其中属性又可分为数据属性和访问器属性。数据属性一般用于存储数据数值;访问器属性不包含数据值,访问器属性多用于get/set操作。本文讨论的setter/getter就是JS对象访问器属性中的get/set操作。
get/set和getter/setter
当属性拥有get/set特性时,属性就是访问器属性。代表着在访问属性或者写入属性值时,对返回值做附加的操作。而这个操作就是getter/setter函数。
它们只能应用到单个属性上,无法应用在整个对象上。getter/setter是隐藏函数,是访问器属性默认拥有的隐藏函数。在读取访问器属性时调用getter,返回有效的值;在写入访问器属性时调用setter函数并传入新值。
不管是对象文字语法中的get a(){…},还是的defineProperty(…)中的显式定义,二者都会在对象中创造一个不包含值的属性,对于这个属性的访问会自动调用一个隐藏函数,它的返回值会被当做属性访问的返回值。
数据属性
数据属性是用于存储数据数值的,因此数据属性具有一个数据值的位置,在这个位置可以读取和写入值。数据属性有4个描述其行为的特性:
- 【Configurable】默认值为true。表示:a、能否通过delete删除属性从而重新定义属性, b、能修改属性的特性 ,c、能够把属性由数据属性修改为访问器属性;
- 【Enumerable】默认值为true,表示能否通过for-in循环返回该属性;
- 【Writable】默认值为true,表示能否修改属性的值(这是与【Configurable】不同之处)
- 【Value】默认值为undefined,这个值即为属性的属性值,我们可以在这个位置上读取属性值,也可以在这个位置上写入属性值。
Object.defineProperty()
Object.defineProperty()方法k修改属性默认的特性,此方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。描述符对象是对象字面量的方法创建的,里面的属性和属性值是要修改的特性和特性值。
需要注意的是:
- 数据属性有4个特性中,除Value外其余三个默认为ture,这是在创建对象并创建属性的情况下的默认值。对于直接通过调用Object.defineProperty()方法创建的属性,这三个特性的默认值均为false。
- 一旦属性被设置成为不可配置的,就不能再把它变回可配置了。因此为了可配置,必须在第一次调用Object.defineProperty()函数时就将默认值修改为true。
访问器属性
访问器属性不包含数据值,他们包含一对getter函数和setter函数。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性是,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性不能直接定义,必须是用Object.defineProperty()来定义。
访问器属性有4个描述其行为的特性:
- 【Configurable】默认值为true
- 【Enumerable】默认值为true,表示能否通过for-in循环返回该属性
- 【Get】在读取属性时调用的函数。默认值为undefined。
- 【Set】在写入属性时调用的函数。默认值为undefined。
由于get和set函数也属于属性的特性,那么他们就有可能出现在Object.defineproperty的第三个参数描述符对象的属性中。
getter/setter创建及删除
getter
- 可以使用数值或字符串作为标识;
- 必须不带参数;
- 它不能与另一个 get或具有相同属性的数据同时出现在一个对象字面量中
- 可通过 delete 操作符删除 getter
getter创建:
- 对象初始化时定义
const obj = {log: ['a', 'b', 'c'],get latest() {if (this.log.length === 0) {return undefined;}return this.log[this.log.length - 1];}
};
console.log(obj.latest);
// expected output: "c"
- 使用defineProperty在现有对象上定义
const obj = {log: ['a', 'b', 'c'],
};
Object.defineProperty(obj, 'latest', {get:function() {return this.log;},
});
console.log(obj.latest);
// expected output: ["a", "b", "c"]
注意:当使用 get 关键字时,它和Object.defineProperty() 有类似的效果,在classes中使用时,二者有细微的差别。当使用 get 关键字时,属性将被定义在实例的原型上,当使用Object.defineProperty()时,属性将被定义在实例自身上。
- 使用计算出的属性名
let expr = 'foo';
let obj = {get [expr]() { return 'bar'; }
};
console.log(obj.foo); // "bar"
getter删除:
使用delete操作符删除 getter
delete obj.latest;
setter
- 它的标识符可以是数字或字符串;
- 必须有一个明确的参数;
- 在对象字面量中,不能为一个已有真实值的变量使用 set ,也不能为一个属性设置多个 set
- 可通过 delete 操作符删除 setter
setter创建:
- 对象初始化时定义
const language = {set current(name) {this.log.push(name);},log: []
};
language.current = 'EN';
language.current = 'FA';
console.log(language.log);
// expected output: Array ["EN", "FA"]
- 使用defineProperty在现有对象上定义
const o = { a:0 };
Object.defineProperty(o, "b", { set: function (x) { this.a = x / 2; } });
o.b = 10; // Runs the setter, which assigns 10 / 2 (5) to the 'a' property
console.log(o.a) // 5
- 使用计算属性名
const expr = "foo";
const obj = {baz: "bar",set [expr](v) { this.baz = v; }
};
console.log(obj.baz); // "bar"
obj.foo = "baz"; // run the setter
console.log(obj.baz); // "baz"
setter删除:
使用delete操作符删除 setter
delete language.current;
应用
JS中setter/getter的实际应用场景之一就是Vue响应式原理。
Vue响应式原理
Vue响应式原理:数据发生变化后重新渲染页面
为实现Vue响应式原理,需要完成的的是:
- 数据劫持 / 数据代理:侦测数据的变化
- 依赖收集:收集视图依赖了哪些数据
- 发布订阅模式:数据变化时,自动“通知”需要更新的视图部分,并进行更新
其中,侦测数据变化便是采用setter/getter完成。在将对象传入Vue实例中的data选项中时,Vue 将遍历此对象所有的 property,并使用 Object.defineProperty 把这些 property 全部转为 getter/setter。每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。
注意:Vue 通过Object.defineProperty来将对象的key转换成getter/setter的形式来追踪变化,但getter/setter只能追踪一个数据是否被修改,无法追踪新增属性和删除属性。故而,Vue 不能检测数组和对象的变化。
参考文章
- 深入理解JavaScript中的属性和特性
- getter
- setter
- vue响应式详解
- 深入响应式原理
JS中setter/getter理解相关推荐
- Javascript基础进阶(十六)JS中面向对象的理解、继承、封装、多态
小编推荐:Fundebug提供JS错误监控.微信小程序错误监控.微信小游戏错误监控,Node.j错误监控和Java错误监控.真的是一个很好用的错误监控费服务,众多大佬公司都在使用. 面向对象编程OOP ...
- 谈谈我对js中闭包的理解
闭包是一个能够访问其他函数作用域的函数. 很显然这样的定义晦涩难懂,很多人都很难理解闭包的真正含义 那么我们就用通俗一点的语言来解析一下什么是闭包 我在知乎上看到一个比较有意思的回答: 由此我们可以通 ...
- js中this的理解
平常用this很多,对this的理解就是this是对应执行环境,然而很多时候效果并不是想要的,最近看了一些谈到this的笔记和书籍,总结下. 对this的误解: this是指向函数本身 先上个demo ...
- JS中call用法理解
call()方法是借用构造函数来实现继承,即在子类型构造函数的内部调用超类型构造函数. 我理解的call()的作用就是改变上下文,即在以下代码中的 function subtype(){superTy ...
- js中深浅拷贝理解与方法
深浅拷贝的方法 堆栈理解 基本数据类型 number.string.boolean.null.undefined 引用数据类型 object.function.array 栈内存 存储基本数据类型内容 ...
- js中call函数理解
一直以来,对call函数都不是很理解,经常看到用,有时候把,觉得挺好理解的,有时候吧,又觉得摸不清头脑,最近在看d3,里面又遇到call,所以,还是得把这个问题理解透彻.现在把我的理解记录如下: ca ...
- JS中prototype的理解
1,JS是基于对象的语言,构造函数本身就是一个对象,当调用new关键字时,会创建一个新对象.2,prototype是对象的一个属性,其可以是一个基本类型,如数字.字符串等,也可以是一个引用类型. 3, ...
- js中arguments的理解
一.在函数调用的时候,浏览器每次都会传递进来两个隐式参数 1.函数的上下文对象this 2.封装实参的对象arguments 二.arguments对象 1.arguments对象实际是所在函数的一个 ...
- JS 中 TDZ 的理解
原文链接:https://acrens.github.io/2017/01/22/2017-01-22-TDZ/ 春节快到了,假期也快到了,空闲之余刷个微博,看见 @ruanyf 提出了一个问题与 T ...
最新文章
- php session_start() 非常慢,PHP session_start()很慢问题分析与解决办法
- linux ssh 设置的相关总结(ssh最大连接数、ssh连接时长、安全性配置等)
- git提交输入密码_git提交到自己的服务器,每次都要输入密码
- CobaltStrike的使用
- 阿里巴巴大数据实践—实时技术
- [蓝桥杯][2019年第十届真题c/c++B组]后缀表达式(解释sum -= 2*a[i])
- (HDU)1061 --Rightmost Digit( 最右边的数字)
- Oracle数据库备份到本地
- 卡诺模型案例分析_需求分析神器 | 卡诺模型
- 如何解决Adobe Flash Player已被屏蔽
- js base64 php,php中的base64decode 与js中的互相转换
- android studio运行时报错AVD Nexus_5X_API_P is already running解决办法
- win7 关闭防火墙
- 信必优荣获BOSS直聘“王者之舟·最爱人才雇主奖”
- 喵喵机和咕咕机哪个好,打印效果大评测!喵喵机p2 VS咕咕机GT1
- 逆序数(inverse number)
- linux下eeprom测试函数,Linux Kernel eisa_eeprom_read函数绕过安全检查漏洞
- 使用devops的团队_DevOps团队如何为网络星期一做准备
- Python:使用f-string保留小数点位数
- 高阶自动驾驶量产背后,最严监管或将加速落地
热门文章
- SMR叠瓦盘原理及终极使用指南
- GoLang之M如何找工作(13)
- 微分方程计算机仿真国内外研究论文,功率键合图法在血液循环系统计算机仿真中的应用,毕业论文...
- Win10配置IIS与 C#/.net项目的发布与IIS部署
- 第31届南京地区研究生通信年会录用论文集
- 阿里云ECS同区域不同账户内网互相访问配置
- Matlab 内置函数作图、实现斐波那契数列的多种函数形式(wzl)
- 人总是欲望着他者的欲望
- 将车辆数据集kitti转换为VOC格式(车辆检测)
- 2019-10-31-ASP.NET-Core-连接-GitLab-与-MatterMost-打造-devops-工具