DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<script>
"use strict";
// 问题1: set 和 deleteProperty 中需要返回布尔类型的值
// 在严格模式下,如果返回 false 的话会出现 Type Error 的异常
const target = {
foo: "xxx",
bar: "yyy",
};
// 因为 JavaScript 的特殊性,代码在运行期间可以随意的去给对象增加成员或者获取对象中成员的信息
/* 所以在过去的时候 JavaScript 没有反射,过去 JavaScript 很随意的把一些方法挂在到 Object 中,
比如:Object.getPrototypeOf() */
// Reflect 也有对应方法 Reflect.getPrototypeOf(),方法的作用是一样的,只是表达语意的问题
// 如果在 Reflect 中有对应的 Object 的方法,那么都建议使用 Reflect 中的方法
const proxy = new Proxy(target, {
get(target, key, receiver) {
// return target[key]
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
// target[key] = value
// Reflect.set() 方法设置成功会返回 true,失败会返回 false
return Reflect.set(target, key, value, receiver);
},
deleteProperty(target, key) {
// delete target[key]
// Reflect.deleteProperty() 方法设置成功会返回 true,失败会返回 false
return Reflect.deleteProperty(target, key);
},
});
proxy.foo = "zzz";
// delete proxy.foo
script>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<script>
"use strict";
// 问题2:Proxy 和 Reflect 中使用的 receiver
// Proxy 中 receiver:Proxy 或者继承 Proxy 的对象
// Reflect 中 receiver:如果 target 对象中设置了 getter,getter 中的 this 指向 receiver
const obj = {
get foo() {
console.log(this);
// 因为这里的 this 指向 Proxy ,所以 this.bar 执行的是代理对象的 get 方法
return this.bar;
},
};
const proxy = new Proxy(obj, {
get(target, key, receiver) {
if (key === "bar") {
return "value - bar";
}
return Reflect.get(target, key, receiver);
},
});
console.log(proxy.foo);
script>
body>
html>

index.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<script type="module">
import { reactive } from "./reactivity/index.js";
const obj = reactive({
name: "zs",
age: 18,
});
obj.name = "lisi";
delete obj.age;
console.log(obj);
script>
body>
html>
index.js
// 判断一个变量是否是对象
const isObject = (val) => val !== null && typeof val === "object";
// 判断对象中有嵌套属性的情况下,属性是否是对象
const convert = (target) => (isObject(target) ? reactive(target) : target);
// 判断某个对象本身是否具有指定的属性
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (target, key) => hasOwnProperty.call(target, key);
export function reactive(target) {
if (!isObject(target)) return;
// 拦截器
const handler = {
get(target, key, receiver) {
// 收集依赖(代码后续补充)
console.log("get", key);
// 如果对象中有嵌套属性,会递归收集下一级属性的依赖
const result = Reflect.get(target, key, receiver);
return convert(result);
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver);
// 在 Proxy 中,set 方法需要返回一个布尔值,表示赋值是否成功,这里默认为 true
let result = true;
if (oldValue !== value) {
Reflect.set(target, key, value, receiver);
// 触发更新(代码后续补充)
console.log("set", key, value);
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
// 触发更新(代码后续补充)
console.log("delete", key);
}
return result;
},
};
return new Proxy(target, handler);
}

effect-demo.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Documenttitle>
head>
<body>
<script type="module">
import { reactive, effect } from "./reactivity/index.js";
const product = reactive({
name: "iPhone",
price: 5000,
count: 3,
});
let total = 0;
// effect 用法与 watchEffect 用法类似,watchEffect 内部就是调用 watchEffect 实现的
// effect 中的函数首先会执行一次
effect(() => {
total = product.price * product.count;
});
console.log(total);
product.price = 4000;
console.log(total);
product.count = 1;
console.log(total);
script>
body>
html>
index.js
// 判断一个变量是否是对象
const isObject = (val) => val !== null && typeof val === "object";
// 判断对象中有嵌套属性的情况下,属性是否是对象
const convert = (target) => (isObject(target) ? reactive(target) : target);
// 判断某个对象本身是否具有指定的属性
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (target, key) => hasOwnProperty.call(target, key);
export function reactive(target) {
if (!isObject(target)) return;
// 拦截器
const handler = {
get(target, key, receiver) {
// 收集依赖
track(target, key); --- 新增
// 如果对象中有嵌套属性,会递归收集下一级属性的依赖
const result = Reflect.get(target, key, receiver);
return convert(result);
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver);
// 在 Proxy 中,set 方法需要返回一个布尔值,表示赋值是否成功,这里默认为 true
let result = true;
if (oldValue !== value) {
Reflect.set(target, key, value, receiver);
// 触发更新(代码后续补充)
console.log("set", key, value);
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
// 触发更新(代码后续补充)
console.log("delete", key);
}
return result;
},
};
return new Proxy(target, handler);
}
let activeEffect = null; --- 新增
export function effect(callback) { --- 新增
activeEffect = callback;
callback(); // 访问响应式对象属性,去收集依赖
activeEffect = null;
}
let targetMap = new WeakMap(); --- 新增
// 收集依赖
export function track(target, key) { --- 新增
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
index.js
// 判断一个变量是否是对象
const isObject = (val) => val !== null && typeof val === "object";
// 判断对象中有嵌套属性的情况下,属性是否是对象
const convert = (target) => (isObject(target) ? reactive(target) : target);
// 判断某个对象本身是否具有指定的属性
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (target, key) => hasOwnProperty.call(target, key);
export function reactive(target) {
if (!isObject(target)) return;
// 拦截器
const handler = {
get(target, key, receiver) {
// 收集依赖
track(target, key);
// 如果对象中有嵌套属性,会递归收集下一级属性的依赖
const result = Reflect.get(target, key, receiver);
return convert(result);
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver);
// 在 Proxy 中,set 方法需要返回一个布尔值,表示赋值是否成功,这里默认为 true
let result = true;
if (oldValue !== value) {
Reflect.set(target, key, value, receiver);
// 触发更新
trigger(target, key); --- 新增
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
// 触发更新
trigger(target, key); --- 新增
}
return result;
},
};
return new Proxy(target, handler);
}
let activeEffect = null;
export function effect(callback) {
activeEffect = callback;
callback(); // 访问响应式对象属性,去收集依赖
activeEffect = null;
}
// 收集依赖
let targetMap = new WeakMap();
export function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
// 触发更新
export function trigger(target, key) { --- 新增
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach((effect) => {
effect();
});
}
}
ref.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script type="module">
import { reactive, effect, ref } from './reactivity/index.js'
const price = ref(5000)
const count = ref(3)
let total = 0
effect(() => {
total = price.value * count.value
})
console.log(total)
price.value = 4000
console.log(total)
count.value = 1
console.log(total)
script>
body>
html>
index.js
// 判断一个变量是否是对象
const isObject = (val) => val !== null && typeof val === "object";
// 判断对象中有嵌套属性的情况下,属性是否是对象
const convert = (target) => (isObject(target) ? reactive(target) : target);
// 判断某个对象本身是否具有指定的属性
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (target, key) => hasOwnProperty.call(target, key);
export function reactive(target) {
if (!isObject(target)) return;
// 拦截器
const handler = {
get(target, key, receiver) {
// 收集依赖
track(target, key);
// 如果对象中有嵌套属性,会递归收集下一级属性的依赖
const result = Reflect.get(target, key, receiver);
return convert(result);
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver);
// 在 Proxy 中,set 方法需要返回一个布尔值,表示赋值是否成功,这里默认为 true
let result = true;
if (oldValue !== value) {
Reflect.set(target, key, value, receiver);
// 触发更新
trigger(target, key);
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
// 触发更新
trigger(target, key);
}
return result;
},
};
return new Proxy(target, handler);
}
let activeEffect = null;
export function effect(callback) {
activeEffect = callback;
callback(); // 访问响应式对象属性,去收集依赖
activeEffect = null;
}
// 收集依赖
let targetMap = new WeakMap();
export function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
// 触发更新
export function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach((effect) => {
effect();
});
}
}
export function ref(raw) { --- 新增
// 判断 raw 是否是ref 创建的对象,如果是的话直接返回
if (isObject(raw) && raw.__v_isRef) {
return;
}
let value = convert(raw);
const r = {
// 标识是否是 ref 对象
__v_isRef: true,
get value() {
track(r, "value");
return value;
},
set value(newValue) {
if (newValue !== value) {
raw = newValue;
value = convert(raw);
trigger(r, "value");
}
},
};
return r;
}
toRefs.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script type="module">
import { reactive, effect, toRefs } from './reactivity/index.js'
function useProduct () {
const product = reactive({
name: 'iPhone',
price: 5000,
count: 3
})
return toRefs(product)
}
const { price, count } = useProduct()
let total = 0
effect(() => {
total = price.value * count.value
})
console.log(total)
price.value = 4000
console.log(total)
count.value = 1
console.log(total)
script>
body>
html>
index.js
// 判断一个变量是否是对象
const isObject = (val) => val !== null && typeof val === "object";
// 判断对象中有嵌套属性的情况下,属性是否是对象
const convert = (target) => (isObject(target) ? reactive(target) : target);
// 判断某个对象本身是否具有指定的属性
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (target, key) => hasOwnProperty.call(target, key);
export function reactive(target) {
if (!isObject(target)) return;
// 拦截器
const handler = {
get(target, key, receiver) {
// 收集依赖
track(target, key);
// 如果对象中有嵌套属性,会递归收集下一级属性的依赖
const result = Reflect.get(target, key, receiver);
return convert(result);
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver);
// 在 Proxy 中,set 方法需要返回一个布尔值,表示赋值是否成功,这里默认为 true
let result = true;
if (oldValue !== value) {
Reflect.set(target, key, value, receiver);
// 触发更新
trigger(target, key);
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
// 触发更新
trigger(target, key);
}
return result;
},
};
return new Proxy(target, handler);
}
let activeEffect = null;
export function effect(callback) {
activeEffect = callback;
callback(); // 访问响应式对象属性,去收集依赖
activeEffect = null;
}
// 收集依赖
let targetMap = new WeakMap();
export function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
// 触发更新
export function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach((effect) => {
effect();
});
}
}
export function ref(raw) {
// 判断 raw 是否是ref 创建的对象,如果是的话直接返回
if (isObject(raw) && raw.__v_isRef) {
return;
}
let value = convert(raw);
const r = {
// 标识是否是 ref 对象
__v_isRef: true,
get value() {
track(r, "value");
return value;
},
set value(newValue) {
if (newValue !== value) {
raw = newValue;
value = convert(raw);
trigger(r, "value");
}
},
};
return r;
}
export function toRefs(proxy) { --- 新增
const ret = proxy instanceof Array ? new Array(proxy.length) : {};
for (const key in proxy) {
ret[key] = toProxyRef(proxy, key);
}
return ret;
}
function toProxyRef(proxy, key) { --- 新增
const r = {
__v_isRef: true,
get value() {
// 这里不需要收集依赖,因为这里返回的是响应式对象
return proxy[key];
},
set value(newValue) {
proxy[key] = newValue;
},
};
return r;
}
computed.html
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Documenttitle>
head>
<body>
<script type="module">
import { reactive, effect, computed } from './reactivity/index.js'
const product = reactive({
name: 'iPhone',
price: 5000,
count: 3
})
let total = computed(() => {
return product.price * product.count
})
console.log(total.value)
product.price = 4000
console.log(total.value)
product.count = 1
console.log(total.value)
script>
body>
html>
index.js
// 判断一个变量是否是对象
const isObject = (val) => val !== null && typeof val === "object";
// 判断对象中有嵌套属性的情况下,属性是否是对象
const convert = (target) => (isObject(target) ? reactive(target) : target);
// 判断某个对象本身是否具有指定的属性
const hasOwnProperty = Object.prototype.hasOwnProperty;
const hasOwn = (target, key) => hasOwnProperty.call(target, key);
export function reactive(target) {
if (!isObject(target)) return;
// 拦截器
const handler = {
get(target, key, receiver) {
// 收集依赖
track(target, key);
// 如果对象中有嵌套属性,会递归收集下一级属性的依赖
const result = Reflect.get(target, key, receiver);
return convert(result);
},
set(target, key, value, receiver) {
const oldValue = Reflect.get(target, key, receiver);
// 在 Proxy 中,set 方法需要返回一个布尔值,表示赋值是否成功,这里默认为 true
let result = true;
if (oldValue !== value) {
Reflect.set(target, key, value, receiver);
// 触发更新
trigger(target, key);
}
return result;
},
deleteProperty(target, key) {
const hadKey = hasOwn(target, key);
const result = Reflect.deleteProperty(target, key);
if (hadKey && result) {
// 触发更新
trigger(target, key);
}
return result;
},
};
return new Proxy(target, handler);
}
let activeEffect = null;
export function effect(callback) {
activeEffect = callback;
callback(); // 访问响应式对象属性,去收集依赖
activeEffect = null;
}
// 收集依赖
let targetMap = new WeakMap();
export function track(target, key) {
if (!activeEffect) return;
let depsMap = targetMap.get(target);
if (!depsMap) {
targetMap.set(target, (depsMap = new Map()));
}
let dep = depsMap.get(key);
if (!dep) {
depsMap.set(key, (dep = new Set()));
}
dep.add(activeEffect);
}
// 触发更新
export function trigger(target, key) {
const depsMap = targetMap.get(target);
if (!depsMap) return;
const dep = depsMap.get(key);
if (dep) {
dep.forEach((effect) => {
effect();
});
}
}
export function ref(raw) {
// 判断 raw 是否是ref 创建的对象,如果是的话直接返回
if (isObject(raw) && raw.__v_isRef) {
return;
}
let value = convert(raw);
const r = {
// 标识是否是 ref 对象
__v_isRef: true,
get value() {
track(r, "value");
return value;
},
set value(newValue) {
if (newValue !== value) {
raw = newValue;
value = convert(raw);
trigger(r, "value");
}
},
};
return r;
}
export function toRefs(proxy) {
const ret = proxy instanceof Array ? new Array(proxy.length) : {};
for (const key in proxy) {
ret[key] = toProxyRef(proxy, key);
}
return ret;
}
function toProxyRef(proxy, key) {
const r = {
__v_isRef: true,
get value() {
// 这里不需要收集依赖,因为这里返回的是响应式对象
return proxy[key];
},
set value(newValue) {
proxy[key] = newValue;
},
};
return r;
}
export function computed(getter) { --- 新增
// 如果 ref 不传参数,默认返回 undefined
const result = ref();
// 在 effect 中执行 getter 时,访问响应式数据属性会收集依赖
// 当数据变化后,会重新执行 effect 函数
effect(() => (result.value = getter()));
return result;
}