-
Notifications
You must be signed in to change notification settings - Fork 4.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ES6 系列之 defineProperty 与 proxy #107
Comments
赞~ 写的很好 易懂 |
watch api 那块代码
所以一开始用 watch 来初始化监听 obj 的时候,就会调用一次注册进去的 callback 吧?感觉有点不太符合平时的逻辑
|
首先感谢大佬分享,然后问一个问题,希望大佬能解答一下,为什么这一块要加这一句
好像理解了,是为了在obj中的value有初始值的情况下能立即在页面上展示吧 |
发现一个小的拼写错误 |
肚子小了整个人都有活力了 |
感觉可以说下 proxy对比defineProperty的区别,以及优势在在哪里耶 |
博主有说啊,proxy 可以代理更多的行为啊,defineProperty 只能代理 get 和 set。 |
这一点我也没看明白,赋值时调用 set 方法就会自动更新 obj 中的 value 属性了。 |
博主写的简单易懂,太适合小白了,感谢。 |
为什么要把watch函数放到自执行函数里面? |
Proxy
Object.defineProperty
|
那proxy 会有 polyfill来支持 IE11以下的浏览器吗 |
应用场景
|
应该是用了ES6之前,模块封装的通用写法。 |
github中文这个屑排版,唉。。。 |
watch api 上方的例子是不是有点问题?
value = value 的话没有办法把值更新到var定义的value上 |
面试官问 :Object.definedProperty 和 Proxy 相比优势和劣势 怎么回答噢? |
应该使用newValue赋值的,笔者笔误了吧。 |
core-js的作者最近很困难 |
前言
我们或多或少都听过“数据绑定”这个词,“数据绑定”的关键在于监听数据的变化,可是对于这样一个对象:
var obj = {value: 1}
,我们该怎么知道 obj 发生了改变呢?definePropety
ES5 提供了 Object.defineProperty 方法,该方法可以在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回这个对象。
语法
参数
举个例子:
虽然我们可以直接添加属性和值,但是使用这种方式,我们能进行更多的配置。
函数的第三个参数 descriptor 所表示的属性描述符有两种形式:数据描述符和存取描述符。
两者均具有以下两种键值:
configurable
enumerable
数据描述符同时具有以下可选键值:
value
writable
存取描述符同时具有以下可选键值:
get
set
值得注意的是:
属性描述符必须是数据描述符或者存取描述符两种形式之一,不能同时是两者 。这就意味着你可以:
也可以:
但是不可以:
此外,所有的属性描述符都是非必须的,但是 descriptor 这个字段是必须的,如果不进行任何配置,你可以这样:
Setters 和 Getters
之所以讲到 defineProperty,是因为我们要使用存取描述符中的 get 和 set,这两个方法又被称为 getter 和 setter。由 getter 和 setter 定义的属性称做”存取器属性“。
当程序查询存取器属性的值时,JavaScript 调用 getter方法。这个方法的返回值就是属性存取表达式的值。当程序设置一个存取器属性的值时,JavaScript 调用 setter 方法,将赋值表达式右侧的值当做参数传入 setter。从某种意义上讲,这个方法负责“设置”属性值。可以忽略 setter 方法的返回值。
举个例子:
这不就是我们要的监控数据改变的方法吗?我们再来封装一下:
watch API
既然可以监控数据的改变,那我可以这样设想,即当数据改变的时候,自动进行渲染工作。举个例子:
HTML 中有个 span 标签和 button 标签
当点击按钮的时候,span 标签里的值加 1。
传统的做法是:
如果使用了 defineProperty:
代码看似增多了,但是当我们需要改变 span 标签里的值的时候,直接修改 obj.value 的值就可以了。
然而,现在的写法,我们还需要单独声明一个变量存储 obj.value 的值,因为如果你在 set 中直接
obj.value = newValue
就会陷入无限的循环中。此外,我们可能需要监控很多属性值的改变,要是一个一个写,也很累呐,所以我们简单写个 watch 函数。使用效果如下:我们来写下这个 watch 函数:
现在我们已经可以监控对象属性值的改变,并且可以根据属性值的改变,添加回调函数,棒棒哒~
proxy
使用 defineProperty 只能重定义属性的读取(get)和设置(set)行为,到了 ES6,提供了 Proxy,可以重定义更多的行为,比如 in、delete、函数调用等更多行为。
Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,ES6 原生提供 Proxy 构造函数,用来生成 Proxy 实例。我们来看看它的语法:
proxy 对象的所有用法,都是上面这种形式,不同的只是handler参数的写法。其中,new Proxy()表示生成一个Proxy实例,target参数表示所要拦截的目标对象,handler参数也是一个对象,用来定制拦截行为。
除了 get 和 set 之外,proxy 可以拦截多达 13 种操作,比如 has(target, propKey),可以拦截 propKey in proxy 的操作,返回一个布尔值。
又比如说 apply 方法拦截函数的调用、call 和 apply 操作。
apply 方法可以接受三个参数,分别是目标对象、目标对象的上下文对象(this)和目标对象的参数数组,不过这里我们简单演示一下:
又比如说 ownKeys 方法可以拦截对象自身属性的读取操作。具体来说,拦截以下操作:
下面的例子是拦截第一个字符为下划线的属性名,不让它被 for of 遍历到。
更多的拦截行为可以查看阮一峰老师的 《ECMAScript 6 入门》
值得注意的是,proxy 的最大问题在于浏览器支持度不够,而且很多效果无法使用 poilyfill 来弥补。
watch API 优化
我们使用 proxy 再来写一下 watch 函数。使用效果如下:
我们也可以发现,使用 defineProperty 和 proxy 的区别,当使用 defineProperty,我们修改原来的 obj 对象就可以触发拦截,而使用 proxy,就必须修改代理对象,即 Proxy 的实例才可以触发拦截。
ES6 系列
ES6 系列目录地址:https://github.com/mqyqingfeng/Blog
ES6 系列预计写二十篇左右,旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容。
如果有错误或者不严谨的地方,请务必给予指正,十分感谢。如果喜欢或者有所启发,欢迎 star,对作者也是一种鼓励。
The text was updated successfully, but these errors were encountered: