# 为什么?

首先,看 函数编程 的 求和

	let name = '向军' ; 
	let grade = [
		{name: 'js' , score: 99} , 
		{name: 'docker' , score: 76} 
	] ; 
	function average(grade , name) {
		let total = grade.reduce((t,l) => t+l.score , 0 ) ; 
		return `${name}的平均成绩是:${total/grade.lengh}` ; 
		//array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
	}
	console.log(average(grade , name ));

对象编程

let user = {
	name:  '向军'  , 
	grade = [
	{name: 'js' , score: 99} , 
	{name: 'docker' , score: 76} 
	] ,
	average: function() {
		let total = this.grade.reduce((t,l) => t+l.score , 0 ) ; 
		return `${this.name}的平均成绩是:${total/grade.lengh}` ; 
		//array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
	}

}
console.log(average());

或者简写

let user = {
	name:  '向军'  , 
	grade = [
	{name: 'js' , score: 99} , 
	{name: 'docker' , score: 76} 
	] ,
	average () {
		let total = this.grade.reduce((t,l) => t+l.score , 0 ) ; 
		return `${this.name}的平均成绩是:${total/grade.lengh}` ; 
		//array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
	}

}
console.log(average());

减少 函数编程 意大利面条式 的程序


遍历

 let user = {
 	name: '向军',
 	'my age': 18 
 }

for(const key in user) {
	console.log(user[key]) ;
}

## 添加 / 删除 属性(方法)

user.age= 19 ; 
user.get=function() {
	return `${this.name}的年龄${this.age}`;
}
console.log(user.get());
delete user.age ; 
console.log(user.get());

## 对象的引用

https://www.bilibili.com/video/av77733273?p=3

## 展示语法 、 参数合并

 //展开语法
let arr = [1,2,3] ;
let a = [... arr , 5, 6 , 7] ; 
console.log(a);


let user = {name: 'a' , age : 22} ;
let hd = {...user , lang: 'zh'};
console.log(hd);


function upload(params) { // 参数合并
	let config = {
		type: '*.jpeg,*.png' ,
		size: 10000 ; 
	} ; 
	config = {...config, ...params};
	console.log(config);
	
}
console.log(upload({size:99 , type: '*.gif'}));

# 解构

## 解构赋值

let user = {name: 'aaa' , age : 18} ;
let {name: n , age: a } = user ; 
console.log(n);
console.log(age);

let user = {name: 'aaa' , age : 18} ;
let {name: name , age: age } = user ; 
console.log(n);
console.log(age);

let user = {name: 'aaa' , age : 18} ;
let {name , age } = user ; 
console.log(n);
console.log(age);
function hd() {
	return {name: 'aaa' , age : 18} ; 
}
let {name , age } = user ; 
console.log(n);
console.log(age);
function user({name, age}) {
	console.log(name, age);
}
user({name: 'a' , age : 22});  // 常用接收语后台传值

let {random} = Math; 
console.log(random()); // 直接random 函数 运行

## 严格模式 解构

https://www.bilibili.com/video/av77733273?p=6

非严格模式

	//'use strict'
	({name , age } = {name: 'a' , age : 22} )  // 非严格模式 这样可以

严格模式

	'use strict'
	let {name , age } = {name: 'a' , age : 22} // 声明语句声明了就行

作用? 健壮

## 解构操作 - 简写 、 变量解构

let web  = {name: 'a' , age : 22}  ; 
let {name } = web ; 

let name = 'aa' , url = 'aaabbbb' ; 
let opt = {name , url } ; 

## 解构操作 、 多层对象

let hd = {
	name : 'aa'  , 
	lesson : {
		title : 'js'
	}
} ; 
let {
	name , 
	lesson : {title }
} = hd ; 
console.log(title);

## 解构 默认值 、 配置项合并

let user = {name:'aa' , url : 'abasbasd'}
let {name , url , title ='hdsfda' } = user ; 
console.log(name , url , title);

可以做参数的合并

function createElement(options) {
	let {
		width= 200 , 
		height = 100 , 
		backgroundColor = 'red' 
	} = options ; 
	const div = document.createElement('div');
	div.style.width = width + 'px' ; 
	div.style.height = height + 'px' ; 
	div.style.backgroundColor = backgroundColor + 'px' ; 
	document.body.appendChild(div);
}
createElement({width:300});

# 原型

## hasOwnProperty 检测


只看自己 , 不看原型

## ‘concat’ in arr 检测

看自己 也看原型 原型链

https://www.bilibili.com/video/av77733273?p=12

## setPrototypeOf(新, 原型)

let a = {name : 'aa'} ; 
let b = {url: 'aba'} ; 
Object.setPrototypeOf(a , b ); 
console.log(a);
function oss(options) {
	if(!options.hasOwnProperty('host')) {
		throw new Error('必须设置主机地址');
	}
}
oss({user : 'admin'}) ;

## 计算属性 stringify 、 assign 使用

 let lessons = [
        {
            title: "媒体查询响应式布局",
            click: 89, 
            price: 12 
        } ,
        {
            title: "FLEX 弹性盒模型",
            click: 45, 
            price: 120 
        } ,
        {
            title: "GRID 栅格系统",
            click: 19, 
            price: 67 
        } ,
        {
            title: "盒子模型详解",
            click: 29, 
            price: 300 
        } ,
    ];
    let res = lessons.reduce((obj , cur , index) => {
        obj[`${cur.title}-${index+1}`] = cur ; 
        return obj ; 
    } , {});
    let s = JSON.stringify(res , null , 2);
    console.log(s);

使用assign

let hd = Object.assign({a:1} ,{b:2});
console.log(hd); //{a:1 , b:2}

function upload(params){
	let options = {
		size: 1999 
	} ; 
	options = Object.assign(options , params);
	console.log(JSON.stringify(options , null , 2 ));
}
upload({size: 99, type: 'jpeg'});


与assign
类似的库
jQuery.extend()
lodash

## Object.keys / Object.values / Object.entries

 let lessons = [
     {
         title: "媒体查询响应式布局",
         click: 89, 
         price: 12 
     } ,
     {
         title: "FLEX 弹性盒模型",
         click: 45, 
         price: 120 
     } ,
     {
         title: "GRID 栅格系统",
         click: 19, 
         price: 67 
     } ,
     {
         title: "盒子模型详解",
         click: 29, 
         price: 300 
     } ,
 ];
 console.log(Object.keys(lessons));
 console.log(Object.values(lessons));
 let a = Object.entries(lessons) //转换为数组形式
 console.log(JSON.stringify(a, null, 3));

## for … in / for … of

in 遍历
of 迭代(不能 迭代 对象)

 let lessons = [
     {
         title: "媒体查询响应式布局",
         click: 89, 
         price: 12 
     } ,
     {
         title: "FLEX 弹性盒模型",
         click: 45, 
         price: 120 
     } ,
     {
         title: "GRID 栅格系统",
         click: 19, 
         price: 67 
     } ,
     {
         title: "盒子模型详解",
         click: 29, 
         price: 300 
     } ,
 ];
 let hd = lessons[0] ; 
for(const key in hd) {
	console.log(hd[key]);
}
for(const interator of hd){ // 这样不行的
}
for(const interator of Object.keys(hd)){
	console.log(hd[iterator]);
}
for(const interator of Object.values(hd)){
	console.log(iterator);
}
for(const interator of lessons){ // 数组 正常迭代
	console.log(iterator);
}
//解构也是可以的
for( const [key , value] of Object.entries(hd)) {
	console.log(value) ; 
}



## 遍历操作和DOM绘制(后面框架会更简单)

 let lessons = [
            {name:'js' , click: 999} , 
            {name:'node' , click: 127}  
        ] ; 
        let ul = document.createElement('ul');
        for (const lesson of lessons) {
            let li = document.createElement('li') ; 
            li.innerHTML = `课程:${lesson.name}${lesson.click}`;
            ul.appendChild(li);
        } 
        document.body.appendChild(ul);

## 浅拷贝

简单理解:(不完全拷贝)

有循环(单层情况 )

        let hd = {name: '后的男人' , url : 'abc.com'} ; 
        let obj = {} ; 
        for (const key in hd) {
            obj[key] = hd[key] ; 
        }
        console.log(obj);


有api

  let hd = {name: '后的男人' , url : 'abc.com'} ; 
  let obj = Object.assign({} , hd);

有合并

        let hd = {name: '后的男人' , url : 'abc.com'} ; 
        let obj = {...hd} ; 
        obj.name = 'xxx'
        console.log(hd)

## 深拷贝

简单理解:(完全拷贝)

上面遍历的问题

 let data = {
      name: 'bsadasfsdafdsafdsafdsafaf'  , 
      user : {
          name: 'sgfag'
      }
  };
  function copy(object) {
      let res = {} ; 
      for(const key in object ) {
          res[key] = object[key] ; 
      }
      return res; 
  }
  let hd = copy(data) ; 
  hd.user.name = 'aaaaaaaaaa'
  console.log(JSON.stringify(hd , null , 2));
  console.log(JSON.stringify(data , null , 2));

递归解决

        let data = {
            name: 'bsadasfsdafdsafdsafdsafaf'  , 
            user : {
                name: 'sgfag'
            }
        };
        function copy(object) {
            let res = {} ; 
            for(const key in object ) {
                res[key] = typeof object[key] == 'object' ? copy(object[key]) : object[key] ; 
            }
            return res; 
        }
        let hd = copy(data) ; 
        hd.user.name = 'aaaaaaaaaa'
        console.log(JSON.stringify(hd , null , 2));
        console.log(JSON.stringify(data , null , 2));

那数组呢?

  let data = {
      name: 'bsadasfsdafdsafdsafdsafaf'  , 
      user : {
          name: 'sgfag'
      } , 
      ar : [1 ,2 ]  
  };
  function copy(obj) {
      let res = obj instanceof Array ? [] : {} ;     
      for(const [k , v ] of Object.entries(obj)) {
          res[k] = typeof v == 'object' ? copy(v) : v ; 
      }
      return res; 
  }
  let hd = copy(data) ; 
  
  console.log(JSON.stringify(hd , null , 2));
  console.log(JSON.stringify(data , null , 2));

## 工厂函数 创建对象

function user(name , age) {
	return {
		name ,
		age , 
		show() {
			console.log(`name=${name} age=${age}`);
		}
	}
}

## 构造函数创建对象


'use strict' ; 

function User(name) {
	this.name = name ; 
	this.show = function()  {
		console.log(this.name);
	}
	return this;  // 可以不返回,系统默认返回
}
let xj = new User('向军') ;
xj.show() ;

let func = xj.show; 
func() ;

这里,不用严格模式,func 的 this 是 window !
因此,一定要严格模式

## js 的 数据类型 、 封装类型 new Object()、Number()、 String()、Boolean()、 new Date()、RegExp() 、 new Function();

js 的构造函数 、 数据类型

let o = new Object() ; 
o.name = 'hdc、' ;
console.log(o);
let n = new Number(1) ;
console.log(n.valueOf());
console.log(n+3);
let s = new String('houdunren');
console.log(s.valueOf());
console.log(s.toUpperCase());


let b = new Boolean(true);
console.log(typeof b.toString); //string
console.log(typeof b.valueOf() ); //boolean


let d = new Date() ;
console.log(d.valueOf());


let r = new RegExp('\\d+'); //数字
console.log(r.valueOf()); // /\d+/
console.log(r.test('abc')); //false



function hd() {}
console.log(hd.constructor); // Function() 


let User = new Function('name' , ` this.name = name ; this.show = function() { console.log(this.name); } `);
let xj = new User('xx') ;
xj.show();

## 对象的 封装、 抽象(这个抽象和java不同)

视频:https://www.bilibili.com/video/av77733273?p=20
js抽象的解释:https://blog.csdn.net/Manson_Wang/article/details/96462628

	function User(name , age ) {
        this.name = name ; 
        this.age  = age ; 
        this.show = function () {
            console.log(`${this.name}${this.info()}`) ;
        }
        this.info = function() {
            return this.age>50 ? '老年' : '青年'  ; 
        }
    }
    let xj = new User('nam' , 10) ; 
	xj.info = function() {return '???'}
    xj.show() ; // 青年???

 function User(name , age ) {
     let data = {name, age} ; 
     this.show = function() {
         console.log(`${data.name}${info()}`) ;
     }
     
     let info = function() {
         return this.age>50 ? '老年' : '青年'  ; 
     }
 }
 let xj = new User('nam' , 10) ; 
 xj.info = function() {return '???'}
 xj.show() ;

## 对象属性 保护(不能修改/删除/重新配置) 、 Object.getOwnPropertyDescriptor

        const user = {
            name : 'aaaaaaaa' , 
            age: 18 
        }
        console.log(
            JSON.stringify(Object.getOwnPropertyDescriptor(user , 'name') , null , 2)
            )
        console.log(
            JSON.stringify(Object.getOwnPropertyDescriptors(user ) , null , 2)
        )

writable: 可修改,
enumerable: 可遍历 / 直接查看,
configurable: 添加 / 删除 属性

## defineProperty

const user = {
    age : 18 
}
console.log(
    JSON.stringify(Object.getOwnPropertyDescriptor(user, 'age'))
)
Object.defineProperty(user , 'name' , {
    value : 'hdr'
}) ; 
console.log(user)
console.log(user.name)
console.log(Object.getOwnPropertyDescriptor(user , 'name'))

'use strict' ; 

const user = {
    age : 18 
}
console.log(
    JSON.stringify(Object.getOwnPropertyDescriptor(user, 'age'))
)
Object.defineProperty(user , 'name' , {
    value : 'hdr'  ,
    writable: true, // 修改
    enumerable: true ,  // 遍历
    configurable : true  // 添加/ 删除 属性 (指定之后不可修改)
}) ; 
console.log(user)
user.name = "向军" ; 
console.log(user)
delete user.name ; 
console.log(user) 


configurable: false 注意点

<mark>configurable: false 之后,不能重新configurable:true 之类的操作</mark>

因为,已经 ‘定义’ 了 ‘不能再定义’

当然,修改其他两个 是可以的

'use strict' ; 

const user = {
    name: '向军' ,
    age : 18 
}
Object.defineProperties(user ,  {
    name: {
        value : 'hdr'  ,
        writable: true,
        enumerable: false , 
        configurable : true 
    } , 
    age: {
        value: '后的男人',
        writable: true , 
        enumerable: false , 
        configurable: true
    }
}) ; 

console.log(user) ; 
console.log(user.name) ; 
console.log(user.age) ;

'use strict' ; 

const user = {
    name: '向军' ,
    age : 18 
}


console.log(
    JSON.stringify(Object.getOwnPropertyDescriptor(user , 'age'))
) ; 
Object.defineProperty(user , 'name' , {
    value: '后盾人' , 
    writable: false 
}); 
console.log(user.name) ; 
user.name = "向军" ; 
console.log(user.name) ; 

严格模式下 报错

## 封闭对象 Object.seal() / Object.isSealed()

'use strict' ; 

const user = {
    name: '向军' ,
    age : 18 
}



console.log(
    JSON.stringify(Object.getOwnPropertyDescriptors(user ), null , 2)
)

Object.seal(user)

console.log(
    JSON.stringify(Object.getOwnPropertyDescriptors(user ), null , 2)
)



Object.seal(user)

<mark>但是 封闭 不等于 configurable : false</mark>

'use strict' ; 

const user = {
    name: '向军' ,
    age : 18 
}

Object.defineProperty(user, 'age' , {
    configurable : false 
})

console.log(
    JSON.stringify(Object.getOwnPropertyDescriptors(user ), null , 2)
)

console.log(Object.isSealed(user))


## 冻结 freeze

'use strict' ; 

const user = {
    name: '向军' ,
    age : 18 
}

Object.freeze(user) ; 
console.log(
    JSON.stringify(Object.getOwnPropertyDescriptors(user) , null , 2)
)

if(!Object.isFrozen(user)) {
    user.site = 'hahaha' ; 
    user.name= '李磊' ; 
    delete user.name ; 
}
console.log(user)

访问器

'use strict' ; 
const user = {
    data: { name: '后盾人', age: 10 } ,
    set age(value) {
        console.log('set...') ; 
        if(typeof value != 'number' || value<10 || value>100){
            throw new Error("年龄格式错误");
        }
        this.data.age = value ; 
    },
    get age() {
        console.log('get...') ; 
        return this.data.age;
    }
};
//user.age=1999 ; 

user.data.age = 11 ; 
console.log(user.data.age) ; 

user.age = 13 ; 
console.log(user.age)


## 访问器 伪造属性

'use strict' ; 
let Lesson = {
    list: [
        {name: 'js', price: 100} ,
        {name: 'mysql', price: 211} ,
        {name: 'vue.js', price: 98} 
    ],
    get total() {
        return this.list.reduce((t,l) =>{
            return t += l.price ;
        }, 0) ;
    }
}; 
console.log(Lesson.total) ; 
Lesson.total = 8388 ; 
console.log(Lesson.total) ;

访问器 优先级高

'use strict' ; 
const user = {
    name: '后盾热',
    age: 10 , 
    set name(value){
        console.log(value+'-后盾热');
    }
};
user.name='hdcms' ; 
console.log(user) ;

Symbol

  • symbol 讲解 - https://blog.csdn.net/LawssssCat/article/details/104234660

访问器 批量设置属性

'use strict' ;
const web = {
    name: '后盾人',
    url: 'houdunren.com' ,
    set site(value) {
        //console.log(value) ; 
        [this.name, this.url] = value.split(',') ; 
    }, 
    get site() {
        return `${this.name}的网址是${this.url}` ;
    }
};
web.site = '开源产品,www.hdcms.com';
console.log(web.site)

## 访问器 优先级

//'use strict' ;
const DATA = Symbol() ;
const user = {
    [DATA]: {
        name : ''
    } , 
    set name(value) {
        this[DATA].name=value;
    },
    get name() {
        return this[DATA].name;
    }
}; 
user.name= "agasd" ;
console.log(user.name) ;

# 构造函数 、 class语法糖 中使用访问器

'use strict' ;
class User {
    constructor(name , age){
        this.data={ name , age };
    }
    get name() {
        return this.data.name;//闭包特性
    } 
    set name(value) {
        if(value.trim()=='' || value.length>20) {
            throw new Error('用户名不合法') 
        }
        this.data.name = value ; 
    }
    get age() {
        return this.data.age;//闭包特性
    } 
    set age(value) {
        this.data.age = value ; 
    }
}


let cms = new User('向军', 19) ;
//cms.name = '' ; 
console.log(cms) ;
console.log(
    JSON.stringify(cms , null , 2)
) ;


加上 Symbol

'use strict' ;
const DATA = Symbol() ;
class User {
    constructor(name , age){
        this[DATA]={ name , age };
    }
    get name() {
        return this[DATA].name;//闭包特性
    } 
    set name(value) {
        if(value.trim()=='' || value.length>20) {
            throw new Error('用户名不合法') 
        }
        this[DATA].name = value ; 
    }
    get age() {
        return this[DATA].age;//闭包特性
    } 
    set age(value) {
        this[DATA].age = value ; 
    }
}


let cms = new User('向军', 19) ;
//cms.name = '' ; 
console.log(cms) ;
console.log(
    JSON.stringify(cms , null , 2)
) ;

# Token 的读写

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script> 'use strict' //token let Request = { set token(content) { localStorage.setItem('token',content) ; }, get token() { let token = localStorage.getItem('token') ; if(!token) { alert('请登录') } return token ; } } Request.token = 'sadgsad5453s4daf3sd1gdsagdsa' ; console.log(Request.token) ; </script>
</body>
</html>


Proxy ***拦截

中文 api - http://caibaojian.com/es6/proxy.html

'use strict' ;
// 对象的***: 对整个对象进行***
const  hd = { name:'后盾人' };
const proxy = new Proxy(hd,{
    get(obj, property) {
        return obj[property] ;
    },
    set(obj, property , value) {
        obj[property] = value ; 
        return true ;  // 严格模式下 必须返回 
    }
});
console.log(proxy.name) ;
proxy.name = '向军'
console.log(proxy.name);
console.log(proxy)
console.log(hd)

***函数

function factorial(num) { //阶乘
    return num==1?1:num *factorial(num-1) ;
}
let proxy = new Proxy(factorial, {
    apply(func , obj , args) {
        console.log(func) ;
    }
});

proxy(5) ;

计时 : console.timeEnd(‘run’) ;

## 阶乘 执行时间

function factorial(num) { //阶乘
    return num==1?1:num *factorial(num-1) ;
}
let proxy = new Proxy(factorial, {
    apply(func , obj , args) {
        console.time('run') ;
        func.apply(this, args) ;
        console.timeEnd('run') ; 
        //console.log(func) ; // function
    }
});

proxy.apply(this,[100]) ;

数组*** 拦截操作

const lessons = [
    {
        title: '媒体查询式布局',
        category: 'css'
    },
    {
        title: 'FLEX 弹性盒模型',
        category: 'css'
    },
    {
        title: 'MYSQL多表查询随意操作',
        category: 'css'
    }
];
let proxy = new Proxy(lessons, {
    get(array,key) {
        const title = array[key].title ; 
        console.log(title) ; 
        const len = 7 ; 
        array[key].title = 
            title.length>len
            ? title.substr(0, len) + '.'.repeat(3) 
            : title ; 
        return array[key] ;
    }
}) ; 
console.log(
    JSON.stringify(proxy[2],null,2)
)

VUEJS 数据绑定的容器更新

https://www.bilibili.com/video/av77733273?p=35

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<input type="text" v-model='title'>
<input type="text" v-model='title'>
<h4 v-bind='title'>这里也会更新</h4>


<script>
function View() {
    let proxy = new Proxy({} , {
        get(obj, property) {} ,
        set(obj,property,value) {
            console.log(value) ; 
        }
    })
    this.init = function() {
        const els = document.querySelectorAll('[v-model]') ;
        els.forEach(item => {
            item.addEventListener('keyup' ,function() { // this 键入的 input
                proxy[this.getAttribute('v-model')] = this.value ; 
            });
        });
    };
}
new View().init() ;
</script>
</body>
</html>

双向页面绑定的 渲染

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>

<input type="text" v-model='content'>
<input type="text" v-model='title'>
<input type="text" v-model='title'>
<h4 v-bind='title'>这里也会更新</h4>


<script>
function View() {
    let proxy = new Proxy({} , {
        get(obj, property) {} ,
        set(obj,property,value) { // 如果是严格模式,要返回true
            document.querySelectorAll(`[v-model="${property}"]`)
            .forEach(item=> {
                item.value=value;
            });
            document.querySelectorAll(`[v-bind="${property}"]`)
            .forEach(item => {
                item.innerHTML = value ; 
            })
            // return true 能避免 'set' on proxy: trap returned falsish for property 'xxx' 异常
        }
    })
    this.init = function() {
        const els = document.querySelectorAll('[v-model]') ;
        els.forEach(item => {
            item.addEventListener('keyup' ,function() { // this 键入的 input
                proxy[this.getAttribute('v-model')] = this.value ; 
            });
        });
    };
}
new View().init() ;
</script>
</body>
</html>
表单校验
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <style>
        .error{
            border-color: red;
        }
    </style>
</head>
<body>

    <input type="text" validate rule='max:12,min:3'>
    <input type="text" validate rule='max:3,isNumber'>

<script>
'use strict' ; 
class Validate{
    max(value , len){
        return value.length <= len ; 
    }
    min(value,len) {
        return value.length >= len ; 
    }
    isNumber(value) {
        return /^\d+$/.test(value);
    }
}
const validate = new Validate() ;
function ProxyFactory(target) {
    return new Proxy(target , {
        get(target, key) {
            return target[key] ;
        },
        set(target, key, el) { // el 传入的 this
            const rules = el.getAttribute('rule');
            let state = rules.split(',').every(rule => { //都是真 才真
                const info = rule.split(':') ; 
                return validate[info[0]](el.value,info[1] ) ;
            })
            el.classList[state?'remove':'add']('error') ; 
            return true ; // 因为是严格模式,所以要返回 true
        }
    });
}
const proxy = ProxyFactory(document.querySelectorAll('[validate]'))
proxy.forEach((item,i) => {
    item.addEventListener("keyup",function() {
        proxy[i] = this ;  //只是为了触发***事件
    })
})
</script>
</body>
</html>

JSON