看Vue源码前的准备工作

最近很慌, 想看源码, 先把简单的相关概念理一理

Object.defineProperty

首先, 概念 :

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。

没啥好说的, 直接上例子

// 定义一个对象
const obj = {
	firstName: 'D',
	lastName: 'Z'
}

// 数据描述符-----------------------------------------------
// 新增一个属性
Object.defineProperty(obj, 'age', {
	configurable: false,  // 不可重新定义
	enumerable: false,    // 不可枚举
	value: 18,			  // 值
	writable: false	   	  // 不可写
})

// 不可重新配置
Object.defineProperty(obj, 'age', {
	configurable: false,  
	enumerable: true
})   // 报错

// 不可删除
delete obj.age  // false
console.log(obj.age) // 18

// 不可枚举
Object.keys(obj)   // ["firstName", "lastName"]

// 不可写
obj.age = 17
console.log(obj.age) // 18

// 存取描述符-----------------------------------------------
Object.defineProperty(obj, 'fullName', {
	get() {
		return  this.firstName + '-' + this.lastName 
	},
	set(value) {
		const arr = value.split('-')
		this.firstName = arr[0]
		this.lastName = arr[1]
	}
})

obj.fullName  // D-Z
obj.fullName = 'A-B' 
obj.lastName  // B
obj.firstName // A

configurable: false 不可重新定义, 也就是说再执行 Object.defineProperty(obj, 'age', {...})将会报错, 并且, 属性不可删除
enumerable: false 不可枚举, 也就是再执行Object.keys()for in 等将取不到该属性
value:18
writable: false 不可写, 也就是对age赋值操作将不会生效, 但不会报错
get取值操作 , function, 默认undefined
set属性值修改时,触发执行该方法 , function, 默认undefined

以上这一些属性, 称为描述符, 需要注意的是, 当使用了getter或setter方法,不允许使用writable和value这两个属性
get set 看起来就很像vue的计算属性

伪数组

伪数组 (ArrayLike) ,又称类数组。是一个类似数组的对象,但是有如下几个特征。
按索引方式储存数据

0: xxx, 1: xxx, 2: xxx...

具有length属性

但是length属性不是动态的,不会随着成员的变化而改变

不具有数组的push(), forEach()等方法

arrayLike.__proto__ === Object.prototype;   //true 
arrayLike instanceof Object; //true 
arrayLike instanceof Array; //false 

以下是常见伪数组:

  • arguments
  • NodeList => document.querySelectorAll(‘div’).constructor.name // NodeList
  • HTMLCollection => document.getElementsByClassName(‘head_wrapper’).constructor.name // HTMLCollection
  • jQuery => $()

转换为真数组方法

  1. 遍历伪数组存入真数组
  2. Array.prototype.splice.call(arrayLike)
  3. Array.from(arrayLike)
  4. […arrayLike]
  5. 原型继承,arrayLike.proto=Array.prototype
  6. 其他工具库中的方法,如jQuery中的makeArray() toArray()等
NodeType

元素,属性,文本等, 都实现了 Node 接口, 都会有NodeType属性, 它标识了节点属于的 类型
常见的有:
1 -> 元素 节点
3 -> 文字节点
8 -> 注释节点
11 -> DocumentFragment 节点

<div class="my">
	123
	<span>456</span>
	<span>789</span>
</div>

上面的html片段, 分别用childNodes和children取值, 结果分别是什么呢

document.querySelector('.my').childNodes // NodeList(5) [text, span, text, span, text]
document.querySelector('.my').children  // HTMLCollection(2) [span, span]

从图中可以看到, my div下, 包含了5个Node, 其中123, 以及两个小红框位置的换行符, 属于 TextNode , span标签属于 ElementNode

在这里插入图片描述
在这里插入图片描述
childNodes和children结果分别是节点list 和 子元素 list

DocumentFragment

文档片段接口,表示一个没有父级文件的最小文档对象.
通常的用例是创建文档片段,将元素附加到文档片段,然后将文档片段附加到DOM树。在DOM树中,文档片段被其所有的子元素所代替。
因为文档片段存在于内存中,并不在DOM树中,所以将子元素插入到文档片段时不会引起页面回流(对元素位置和几何上的计算)。因此,使用文档片段通常会带来更好的性能。

let content = document.createDocumentFragment()
let el = document.querySelector('.nums')
content.appendChild(el)
// 这个时候 .nums 元素会从页面消失, 存入content这个Fragment片段
Proxy

Proxy用于修改某些操作的默认行为,也可以理解为在目标对象之前架设一层拦截,外部所有的访问都必须先通过这层拦截,因此提供了一种机制,可以对外部的访问进行过滤和修改。这个词的原理为代理,在这里可以表示由它来“代理”某些操作,译为“代理器”。

var obj = new Proxy({}, {
  get(target, key, receiver) {
    console.log(`getting ${key}!`)
    return Reflect.get(target, key, receiver)
  },
  set(target, key, value, receiver) {
    console.log(`setting ${key}!`)
    return Reflect.set(target, key, value, receiver)
  }
})

上面代码对一个空对象架设了一层拦截,重新定义了属性的读取(get)和设置(set)行为。对设置了拦截行为的对象obj,去读写它的属性,用自己的定义覆盖了语言的原始定义,运行得到下面的结果

obj.count = 1
//  setting count!
++obj.count
//  getting count!
//  setting count!
//  2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值