从Object.defineProperty到Vue.extend
前言
本文就Object.defineProperty()方法开始分析数据响应式前置条件;以及对Object.freeze()方法进行联想;最后到element-ui源码分析,探索extends以及Vue.extend。
一、Object.defineProperty()
Object.defineProperty()
静态方法会直接在一个对象上定义一个新属性,或修改其现有属性,并返回此对象
。(Proxy
返回的是一个新对象
)
该方法接受三个参数
Object.defineProperty(obj, prop, descriptor)
obj:要定义属性的对象
prop:一个字符串或 Symbol,指定了要定义或修改的属性键。
descriptor:要定义或修改的属性的描述符。
descriptor中,大家最熟悉的一定是get
和set
const obj = {}
Object.defineProperty(obj, 'age', {
get() {
return 18
},
set() {
return 81
}
})
obj.age = 1
console.log(obj.age, 'age') // 18
给对象中的属性设置值,会走set方法;读取值,会走get方法,所以上面代码虽然改变了age的值,但是最终读取的是固定的值。想要让数据实现响应式,应该让get和set方法都返回相同的值。
const obj = {}
Object.defineProperty(obj, 'age', {
get() {
return age
},
set(val) {
age = val
}
})
obj.age = 1
console.log(obj.age, 'age') // 18
当然这并不是实现数据响应式的全部原理,本文侧重点不在这块。
descriptor中,还有几个同样也非常重要的特性。
writable:为 false 时,该属性被称为“不可写的”,简单来说就是只读。默认值为false
enumerable:为 false 时,该属性不可被 Object.assign() 或展开运算符所考虑,简单来说就是不能进行for...in 和 Object.keys(),默认值为false
configurable:为 false 时,不可以从对象中删除以及其特性(除了 value 和 writable)不可以更改,简单来说就是不能进行delete操作,默认值为false
二、Object.freeze()
Object.freeze()
静态方法可以使一个对象被冻结。冻结对象可以防止扩展,并使现有的属性不可写入和不可配置。被冻结的对象不能再被更改:不能添加新的属性,不能移除现有的属性,不能更改它们的可枚举性、可配置性、可写性或值,对象的原型也不能被重新指定。freeze() 返回与传入的对象相同的对象。(简单来说就是使对象不具备响应式,不会被劫持
)
该方法只能对单层属性进行冻结,也就是浅冻结
;如果想要对于多层嵌套属性进行冻结,需要使用递归自行实现。
联想
Object.freeze()
和下面代码是不是就是等价的呢?
Object.defineProperty(obj, '', {
writable: false,
configurable: false,
})
三、extends
extends允许声明扩展另一个组件 (可以是一个简单的选项对象或构造函数),而无需使用 Vue.extend。这主要是为了便于扩展单文件组件
。
平时在工作中,发现组件有BUG,提PR时间太久;想要改组件,于是有些同学就把源码拉下来,直接在上面改,再发布到npm私服上面。如果不改源码,我们继承原组件,然后再上面改造,那么extends来了。
节省时间,附上大佬的视频和文章教学 => element-ui Form二次修改
四、Vue.extend
Vue.extend使用基础 Vue 构造器,创建一个“子类”。参数是一个包含组件选项的对象。
element-ui的消息组件是通过函数调用实现的(this.$message),它挂在vue实例上。原理很简单,调用函数的时候向dom中添加一个div,简单来说就是createElement和appendChild的升级版。
推荐 vue-helper
插件,快速查看 element-ui 源码。核心代码如下。
不浪费时间,附上大佬的文章 => this.$toast() 了解一下?
总结
知识点都是零散的,需要我们联想、整合。