06/ isRef
通过 __v_isRef 属性 判断是否是 ref 的实例。这个没啥好说的。vue.global.js 源码:
function isRef(r) { return Boolean(r && r.__v_isRef === true); }
07/unref
- 使用.value的语法糖 unref 是一个语法糖,判断是不是 ref 的,如果是则取.value,不是的话取原型。vue.global.js 源码:
function unref(ref) { return isRef(ref) ? ref.value : ref; }
- unref 的用途 普通对象直接
.属性
即可使用,但是 ref 却需要.value才可以,混合使用的时候容易晕头,尤其在函数内部接收参数的时候,无法确定传入的是 reactive 还是 ref,如果每次都用 isReactive 或者 isRef 来判断类型,然后决定是否用.value,那就太麻烦了。于是有了这个语法糖。
08/ toRef 和 toRefs
toRef 可以用来为源响应式对象上的 property 性创建一个
ref
。然后可以将 ref 传递出去,从而保持对其源 property 的响应式连接。toRefs 将响应式对象转换为普通对象,其中结果对象的每个 property 都是指向原始对象相应 property 的ref
。
话说,官网的解释为啥总是这么令人费解呢?我们还是先看看例子
setup () { /** * 定义 reactive * 直接解构属性,看响应性 * 使用toRef解构,看响应性 * 使用toRefs解构,看响应性 * 按钮只修改reactive */ const person = reactive({ name: 'jyk', age: 18 }) console.log('person ', person ) // 直接获取属性 const name = person.name console.log('name ', name ) const refName = toRef(person, 'name') console.log('refName ', refName ) const personToRefs = toRefs(person) console.log('personToRefs ', personToRefs ) const update = () => { // 修改原型 person.name = new Date() } return { person, // reactive name, // 获取属性 refName, // 使用toRef personToRefs, update // 修改属性 } }
当我们修改person的属性值的时候,toRef 和 toRefs 的实例也会自动变化。而直接获取的name属性并不会变化。
toRef 就是想实现直接使用对象的属性名,并且仍然享有响应性的目的。toRef 就是对reactive 进行解构,然后仍然享有响应性的目的。
其实,说是变成了ref,但是我们看看打印结果就会发现,其实并不完全是ref。
toRef
toRefs
看类名和属性,toRef 和 ref 也是有区别的。
09/ toRef 为啥可以响应
toRef 也是一个语法糖。
如果使用常规的方式对 reactive 进行解构的话就会发现,虽然解构成功了,但是也失去响应性(仅限于基础类型的属性,嵌套对象除外)。
那么如何实现解构后还具有响应性呢?这时候就需要使用 toRef 了。
看上面那个例子,使用 refName 的时候,相当于使用 person['name'],这样就具有响应性了。
你可能会问,就这?对就是这么简单,不信的话,我们来看看源码:
function toRef(object, key) { return isRef(object[key]) ? object[key] : new ObjectRefImpl(object, key); } class ObjectRefImpl { constructor(_object, _key) { this._object = _object; this._key = _key; this.__v_isRef = true; } get value() { return this._object[this._key]; // 相当于 person['name'] } set value(newVal) { this._object[this._key] = newVal; } }
看 get 部分,是不是 相当于 person['name'] ?
另外,虽然 toRef 看起来好像是变成了 ref,但是其实只是变成了 ref (RefImpl)的双胞胎兄弟(ObjectRefImpl),并没有变成 ref(RefImpl)。ref 是 RefImpl, 而 toRef 是 ObjectRefImpl,这是两个不同的class 。toRef 可以看做是 ref 同系列的 class,后面还有一个同系列的。
10/ toRefs
了解 toRef 之后,toRefs 就好理解了,从表面上看,可以把 reactive 的所有属性都解构出来,从内部代码来看,就是把多个 toRef 放在了数组(或者对象)里面。
function toRefs(object) { if ( !isProxy(object)) { console.warn(`toRefs() expects a reactive object but received a plain one.`); } const ret = isArray(object) ? new Array(object.length) : {}; for (const key in object) { ret[key] = toRef(object, key); } return ret; }