Class
JavaScript中类的定义及继承,extends 实现对对象的继承,super用于实现父类中的constructor方法,并将参数传递给父类。
// 人类
class people {
_name;
_age;
get name() {
return this._name
}
set name(newval) {
this._name = newval
}
get age() {
return this._age
}
set age(newval) {
this._age = newval
}
sleep() {
console.log(`${this._name}在睡觉`);
}
static isPeople(key) {
Reflect.has(this, key) && console.log(`${key} in people`);
}
constructor(name, age) {
this._age = age;
this._name = name;
}
}
// 教师类
class teacher extends people {
grade;
curse;
teach() {
console.log(`${this.name}在好好教${curse}!!`);
}
static play() {
console.log("教师有寒暑假");
}
constructor(name, age, grade, curse) {
super(name, age);
this.grade = grade;
this.curse = curse;
}
}
//学生类
class student extends people {
grade;
curse;
study() {
console.log(`${this.name}在好好学习!!`);
}
static play() {
console.log("学生都需要运动");
}
constructor(name, age, grade, curse) {
super(name, age);
this.grade = grade;
this.curse = curse;
}
}
Reflect:
Reflect是JavaScript中的全局对象,提供操作JavaScript对象的方法,类似与Object操作对象的方法。用于解决Object方法过于臃肿的问题,对大多数的Object方法进行了实现,同时对于对象的操作返回操作的结果,如返回对象的set操作结果,在某些场景下可以进行监听操作。
Proxy:
Proxy是一个js类,用于实现对对象的代理操作避免直接操作原始数据对象。
const objProxy = new Proxy(student1, {
set(target, key, value, receiver) {
console.log('target,key,value,receiver', target, key, value, receiver);
},
get(target, key, receiver) {
console.log('target,key,value,receiver', target, key, receiver);
},
has(target, key) {
console.log('判断对象是否含有该属性');
},
getPrototypeOf() {
console.log('获取对象的原型');
},
getOwnPropertyDescriptor() {},
setPrototypeOf() {
console.log('设置原型继承');
},
isExtensible() {
console.log('判断对象属性是否可以扩展');
},
defineProperty() {
console.log('监听对象属性描述符');
},
deleteProperty() {
console.log("删除对象属性操作");
},
apply(target, thisArg, argArray) {
return target.apply(thisArg, argArray)
},
construct(target, argArray, newTarget) {
return new target(...argArray)
}
})
Vue2中响应式实现的原理。
利用Object.defineProperty()接口实现对对象的监听。
const obj = {
name:'peter',
age:18,
foo1:function(){
console.log('我是obj对象的方法')
}
}
Object.keys(obj).forEach(key => {
let value = obj[key];
Object.defineProperty(obj, key, {
get() {
console.log(`获取了${key}属性`);
return value
},
set(newValue) {
value = newValue;
show(key)
console.log(`设置了${key}的值---${newValue}`);
}
})
})
function show(params) {
console.log(`监听到${params}发生改变的function`);
}
console.log(obj.name); // 监听到name发生改变的function
//response.js:131 设置了name的值---alison
obj.foo1();//获取了foo1属性
//response.js:115 我是obj对象的方法>>>
利用Object.defineProperty()实现监听的缺陷。
1、Object.defineProperty()API设计的初衷不是为了实现对对象的监听,是为了对对象的属性进行修改定义,如enumerable,writable,configurable等。
2、对于对象属性的添加和删除监听需要搭配其它方法进行,无法直接实现。
Vue3中响应式的实现原理:
核心思想:
利用Proxy的代理操作内的get、set,对对象属性的访问及改变进行监听,利用代理对象每次访问get操作的target及key,在全局对象中找寻代理对象属性相应的依赖函数或方法,执行依赖函数或方法。
First:
创建依赖收集类:用于收集对象属性对应的依赖函数或方法。
class Depend{
constructor(){
this.activeReactiveFns = new Set();
};
add(){
if(activeReactiveFn){
this.activeReactiveFns.add(activeReactiveFn)
}
};
notify(){
this.activeReactiveFns.forEach(_=>_())
}
}
Second:
封装函数实现传递target、key返回对象属性对应的依赖对象depend。
const targetWeakMap = new WeakMap;
funciton getDepend(target,key){
let map = targetWeakMap.get(tagget);
if(!map){
const map = new Map();
targetWeakMap.set(target,map)
}
let depend = map.get(key);
if(!depend){
depend = new Depend;
}
return depend
}
Third:
封装函数收集对象属性依赖。
let activeReactiveFn = null;
watchFn(fn){
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
Fourth:
封装函数,利用Proxy的捕获器将目标对象转化为响应式对象reactiveObj。
function ReactiveObj(target){
return new Proxy(target,{
get(target,key,receiver){
const depend = getDepend(target,key);// 收集依赖函数
depend.add();
return Reflect.get(target,key,receiver);
},
set(target,key,newval,receiver){
Reflect.set(target,key,newval);
const depend = getDepend(target,key);
depend.notify(); // 执行依赖函数
}
})
}
Last:
将需要监听的对象转化为响应式对象,添加响应式函数。
const obj ={
name:'Alison',
age:22
}
const objProxy = Reactive(obj);
watch(_=>{
console.log(objProxy.name); // 收集依赖
})
obj.name = 'Alen';
结合Class使用实际效果,响应式对象属性发生变化时,执行相应的依赖函数。
// 人类
class people {
_name;
_age;
get name() {
return this._name
}
set name(newval) {
this._name = newval
}
get age() {
return this._age
}
set age(newval) {
this._age = newval
}
sleep() {
console.log(`${this._name}在睡觉`);
}
static isPeople(key) {
Reflect.has(this, key) && console.log(`${key} in people`);
}
constructor(name, age) {
this._age = age;
this._name = name;
}
}
// 教师类
class teacher extends people {
grade;
curse;
teach() {
console.log(`${this.name}在好好教${curse}!!`);
}
static play() {
console.log("教师有寒暑假");
}
constructor(name, age, grade, curse) {
super(name, age);
this.grade = grade;
this.curse = curse;
}
}
//学生类
class student extends people {
grade;
curse;
study() {
console.log(`${this.name}在好好学习!!`);
}
static play() {
console.log("学生都需要运动");
}
constructor(name, age, grade, curse) {
super(name, age);
this.grade = grade;
this.curse = curse;
}
}
const s1 = new student('alison', 24, '三年级', 'English');
const t1 = new teacher('alin', 32, '高一', 'physical');
// 响应式监听对象属性的访问与修改
let activeReactiveFn = null;
// 全局收集依赖对象
const targetMap = new WeakMap();
// 依赖收集类
class Depend {
constructor() {
this.activeReactiveFns = new Set();
};
addDepend(...fn) {
this.activeReactiveFns.add(...fn)
};
add() {
if (activeReactiveFn) {
this.activeReactiveFns.add(activeReactiveFn);
}
};
notify() {
this.activeReactiveFns.forEach(_ => _())
}
}
// 全局搜集依赖函数
function getDepend(target, key) {
let map = targetMap.get(target);
if (!map) {
map = new Map;
targetMap.set(target, map);
}
let depend = map.get(key);
if (!depend) {
depend = new Depend;
map.set(key, depend);
}
return depend
}
// 响应式函数封装
function watchFn(fn) {
activeReactiveFn = fn;
fn();
activeReactiveFn = null;
}
// 添加对象为响应式对象
function addProxyDepend(target) {
return new Proxy(target, {
get(target, key, receiver) {
// 根据target.key获取对应的depend
const depend = getDepend(target, key);
//给对应的depend收集依赖
depend.add();
return Reflect.get(target, key, receiver)
},
set(target, key, newval, receiver) {
Reflect.set(target, key, newval, receiver);
//获取对象对应的依赖
const depend = getDepend(target, key);
// 执行依赖函数
depend.notify();
}
})
}
// 创建对t1象代理
const t1Proxy = addProxyDepend(t1);
const s1Proxy = addProxyDepend(s1);
// 创建s1对象代理
function foo1() {
console.log('ts1.age监听1', t1Proxy.age);
}
// watchFn(foo1)
watchFn(function () {
console.log('t1Proxy.name监听', t1Proxy.name);
})
t1Proxy._name = 'peter';
(function name(params) {
let calc = 0;
setInterval(() => {
calc += 1;
t1Proxy._name = calc
}, 3000)
})()