1代理Proxy
1.什么是代理Proxy拦截?
可以对对象,函数,数组进行拦截,将其原本的函数操作改写。
Proxy在目标对象前设一个拦截层,外界对该对象的访问都必须先通过这层拦截,因此提供了一种机制可以对外界的访问进行过滤和改写。
1.obj是原对象,property是实参,函数是要进行的操作
"use strict"
const hd = {name:"fff", age :10};
const proxy = new Proxy(hd, {
get(obj, property){
return obj[property];
},
set(o,p,value){
o[p] = value;
return true;
}
});
console.log(proxy.name);
proxy.name = "lxj";
proxy.age = 23;
console.log(proxy.name);
console.log(proxy);
2.数组 let proxy = new Proxy(lessons, {get (array,key){}})
console.log(proxy[1])
arr是lessons,是原数组, key是下方的“1”,
3.函数代理:function是原函数,
let proxy = new Proxy(func,{
apply(func, obj, args){}
})
proxy.apply({},[5]);
2用代理做数据双向绑定
<body>
<input type="text" v-model="content" />
<input type="text" v-model="title" />
<input type="text" v-model="title" />
<h4 v-bind="title">这里 </h4>
</body>
<script>
function View() {
let proxy = new Proxy({},{
get(obj,property){},
set(obj,property,value){
// console.log(obj);obj是空因为没有拦截对象或函数数组
//property是刚才传递过来的title,value是发生改变的输入框的内容
document.querySelectorAll(`[v-model="${property}"]`).forEach(item =>{
item.value = value;
//选择所有v-model="title"的文本框,其框的值为value。
});
document.querySelectorAll(`[v-bind="${property}"]`).forEach(item =>{
item.innerHTML = value;
//v-bind="title"的元素的显示为value
})
}
})
this.init=function () {
const els = document.querySelectorAll("[v-model]"); //得到属性名为v-model的元素
els.forEach(item => {
item.addEventListener("keyup",function () { //遍历这些元素组成的数组,添加监听事件,检测到键盘抬起,做如下动作
console.log(this);
proxy[this.getAttribute("v-model")] = this.value;
//this.getAttribute("v-model")的值是title。this.value是当前输入框接受到的内容
//在代理对象proxy中给属性名为title的属性添加值为此输入框的内容,即将我们需要存储的数据存储在此对象中,调用访问器set
})
})
}
}
new View().init(); //调用init函数
3.表单验证
表单验证,设定条件,取得元素与条件,存入代理,遍历,调用验证方法,通过添加样式来提示是否符合条件。
以后写验证不一定自己手打,用大家常用的库。
1.数组 every() 方法用于检测数组所有元素是否都符合指定条件(通过函数提供)。
every() 方法使用指定函数检测数组中的所有元素:
如果数组中检测到有一个元素不满足,则整个表达式返回 false ,且剩余的元素不会再进行检测。
如果所有元素都满足条件,则返回 true。
注意: every() 不会对空数组进行检测。
注意: every() 不会改变原始数组。
2.定义和用法
split() 方法用于把一个字符串分割成字符串数组。
语法
stringObject.split(separator,howmany)
参数 描述
separator 必需。字符串或正则表达式,从该参数指定的地方分割 stringObject。
howmany 可选。该参数可指定返回的数组的最大长度。如果设置了该参数,返回的子串不会多于这个参数指定的数组。如果没有设置该参数,整个字符串都会被分割,不考虑它的长度。
返回值
一个字符串数组。该数组是通过在 separator 指定的边界处将字符串 stringObject 分割成子串创建的。返回的数组中的字串不包括 separator 自身。
但是,如果 separator 是包含子表达式的正则表达式,那么返回的数组中包括与这些子表达式匹配的字串(但不包括与整个正则表达式匹配的文本)。
提示和注释
注释:如果把空字符串 ("") 用作 separator,那么 stringObject 中的每个字符之间都会被分割。
注释:String.split() 执行的操作与 Array.join 执行的操作是相反的。
<body>
<input type="text" validate rule = "max:12,min:3"/>
<input type="text" validate rule = "max:3,isNumber"/>
</body>
<style>
.error{
border: solid 2px red;
}
</style>
<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);
//以数字开头的一个或多个数字的字符串
}
}
function ProxyFactory(target) { //代理工厂,
return new Proxy(target, {
get(target,key){
return target[key];
},
set(target,key, el){
//el保存的是的事当前表单元素
// console.log(key);
const rule = el.getAttribute("rule");
// console.log(rule);
const validate = new Validate(); //生成一个验证类
let state = rule.split(",").every(rule => { //按逗号将两条规则拆分
const info = rule.split(":"); //按冒号将验证函数名和参数拆分
console.log(info);
return validate[info[0]](el.value, info[1]); //实参则是框内的值,和最大值或最小值,在此处调用验证函数
// return true;
});
console.log(state);
el.classList[state?"remove":"add"]("error"); //状态为真移除“错误”样式,状态为假添加样式。
return true;
},
});
}
const proxy = ProxyFactory(document.querySelectorAll("[validate]"))
//创建一个代理,代理需验证的元素
// console.log(proxy);
proxy.forEach((item,index) =>{
// console.log(item);
item.addEventListener("keyup", function () {
proxy[index] = this;
//只为触发代理的set函数,没有其他作为。
})
});
</script>
JSON数据
JSON是结构清晰,方便书写的交流通用格式,方便各种语言之间传递数据。配置文件、包管理等。
标准JSON格式是键值对,键值与属性用双引号包裹,
{
“name”:“dkjfaka”
}
2把对象、数组转成JSON格式
1.把对象转成JSON格式json = JSON.stringify(data,保留某个元素,tab制表位的数量)
2.
php的json转换成对象
let phpJSON = {"url":"kajdkjakf"}
;
let obj = JSON.parse(phpJSON);
obj便是一个对象,php-》json-》js
let data = {
name:"jha",
data:{
title:"php"
}
};
let json = JSON.stringify(data);
console.log(json);
3.toJSON,序列化。转换成json时的定制内容
toJSON:function(){
return 。。。
}
4.json -》obj
let obj = JSON.parse(json,(key,value)=》{
做一些操作
return value;
})
原型链
let arr = [];
console.log(arr.proto.proto == Object.prototype);
1.获取对象的原型
Object.isPrototypeOf(hd)
let hd = {};
let xj = {};
console.log(Object.isPrototypeOf(hd) == Object.isPrototypeOf(xj));
2没有原型的对象:
完全数据字典对象
let xj = Object.create(null, {
name:{
value:“jsdkjf”
}
});
console.log(xj);
let hd = {};
console.log(hd);
let xj = Object.create(null, {
name:{
value:"jsdkjf"
}
});
console.log(xj);
{}
: {…}
defineGetter: function defineGetter()
defineSetter: function defineSetter()
lookupGetter: function lookupGetter()
lookupSetter: function lookupSetter()
proto:
constructor: function Object()
hasOwnProperty: function hasOwnProperty()
isPrototypeOf: function isPrototypeOf()
propertyIsEnumerable: function propertyIsEnumerable()
toLocaleString: function toLocaleString()
toSource: function toSource()
toString: function toString()
valueOf: function valueOf()
<get proto()>: function proto()
<set proto()>: function proto()
找到原型.html:13:13
{…}
name: “jsdkjf”
3 proto:每个对象的__proto__属性指向自身构造函数的prototype。
prototype是构造函数在创建对象后所能被对象使用的原型方法
1.每个对象都具有一个名为__proto__的属性;
2.每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就是一个对象(JS中函数同样是对象),所以prototype同样带有__proto__属性);
3.每个对象的__proto__属性指向自身构造函数的prototype
let hd = {};
console.log(hd);
// let xj = Object.create(null, {
// name:{
// value:"jsdkjf"
// }
// });
console.log(hd.__proto__);
hd.__proto__.render = function () {
console.log("kjsdkfj");
};
hd.render();
4上述系统构造原型的体现
对象的obj.__proto__就是原型的Object.prototype
let obj = {};
console.log(obj.__proto__ == Object.prototype);
let arr = [];
console.log(arr.__proto__ == Array.prototype);
let arr = [];
console.log(arr.__proto__ == Array.prototype);
Array.prototype.show=function(){
console.log("aksjdhaj");
}
arr.show();
5设置一个对象的原型
设置Object.setPrototypeOf
获取Object.getPrototypeOf
let hd = {
name:"dj"
}
let xj = {
name:"xj"
}
Object.setPrototypeOf(hd,xj);
console.log(hd);
6 原型中constructer的引用
在此处User.prototype是重新定义了对象的.prototype,所以要把constructor:User在添加进对象的.prototype中,否则这个对象的对象的.prototype只有一个show函数了。
function User(name) {
this.name = name;
}
User.prototype={
show(){
console.log(this.name);
},
constructor:User
}
let lisi = new User.prototype.constructor("里斯");
lisi.show();
7根据对象得到原型中的构造函数,根据构造函数创建对象==》根据对象创建对象。
function User(name) {
this.name = name;
}
User.prototype={
show(){
console.log(this.name);
},
constructor:User
//一定要有这一个,将原型中的构造函数引用。
}
let lisi = new User("里斯");
console.log(lisi);
function createByObject(obj, ...args) {
const constructor = Object.getPrototypeOf(obj).constructor;
console.log(constructor(...args));
return new constructor(...args);
}
let xj = createByObject(lisi, "ixngjia");
xj.show();
8原型链的检测 instanceof
1.//instanceof:检测a的原型链上是否有A.prototype
function A() {
}
let a = new A();
//instanceof:检测a的原型链上是否有A.prototype
console.log(a instanceof A);
2.b.isPrototypeOf(a) b在a的原型链上吗,b是a的父级吗?
let b={};
let c={};
console.log(b.isPrototypeOf(a));
- in检测所有属性
“web” in a web属性是否在a中或a的原型链上呢?
let b={ url:"jksdfja"};
let c={name:"jksdhfjks"};
Object.prototype.web="jsajfsj";
console.log("web" in a);
4.检测当前对象属性:a.hasOwnProperty(“web”)
let b={ url:"jksdfja"};
let c={name:"jksdhfjks"};
Object.prototype.web="jsajfsj";
console.log(a.hasOwnProperty("web"));//false
9想用的函数不在原型链上怎么借用?call apply, bind
DOM借用数组的filter,利用call
let arr = [2,5,7];
let res = arr.filter(item => {
return item>4;
});
console.log(res);
let btns = document.querySelectorAll("button");
let a1 = [].filter.call(btns, item =>{
return item.hasAttribute("class");
});
console.log(a1);
10合理的构造函数声明方法
是把属性放在构造函数中,而方法不放在构造函数中。放在构造函数的原型中。
11 this指向当前对象,不受原型的影响
12 不可再系统Obj中追加方法
所有对象原型链最顶层都是Object,像下面这样做虽然方便但容易造成混乱。
<button onclick="this.hide()">1</button>
</body>
<script>
Object.prototype.hide=function () {
this.style.display="none";
}
</script>
13合适的获取和设置原型的方法
Object.getPrototypeOf(obj)
Object.setPrototypeOf(obj, hd
)
2.不太好的设置原型方法__proto__ 它也是既能设置也能获取原型。
它并不是一个严格意义的属性,是一个访问器getter和setter,会对设置的值进行判断如果不是对象就不能设置原型。若非要设置非对象obj.proto = “dfas”.可以先使得原型为空,添加此属性
obj.proto = hd
console.log(obj.proto)
3.create只能设置原型不能获取原型。
let hd = Object.create(user);
14继承:
1.继承是原型的继承,不是改变构造函数的原型
hd.prototype.proto = user.prototype
2.Admin.prototype = Obiect.create(User.prototype);
Object,defineProperty(Admin.prototype,“constructor”,{
value: Admin,
enumerable:false
});
15使用父类构造函数进行初始化
User.call(this,name,age);要把当前对象传递过去否则不成功
function User(name, age) {
this.name=name;
this.age=age;
}
User.prototype.show=function(){
console.log(this.name,this.age);
}
function Admin(name, age) {
User.call(this,name,age);
}
Admin.prototype=Object.create(User.prototype);
let xj = new Admin("hdjh", 12);
xj.show();
16对象工厂
function User(name, age) {
this.name=name;
this.age=age;
}
function admin(name, age) { //对象工厂
const instance = Object.create(User.prototype); //新的对象
console.log(instance);
User.call(instance,name,age);
instance.role = function () {
console.log("role");
};
instance.show=function(){
console.log(this.name,this.age);}
return instance;
}
let xj = new admin("刘兴加", 23);
xj.show();
xj.role();
17合并类实现类似多继承mixin方法
将不同的对象合并取得它们的方法
member.prototype = Object.assign(member.prototype,Request,Credit);
这样member就继承了二者的方法和属性。实现了多继承。
此时member调用request方法的super指向的是request的原型,因为上述的赋值是引用其他类的函数,并不是这个函数就在member的原型中了。
18Tab选项卡效果基类、业务管理类、开放api
tab构造函数传参方式采用了args,接收到对象后,在与默认参数合并。
所有的动作再开始时重置,默认a1.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<style>
* {
padding: 0;
margin: 0;
}
body {
padding: 20px;
display: flex;
justify-content: center;
align-items: flex-start;
width: 100vw;
height: 100vh;
}
main {
width: 400px;
flex-direction: column;
position: relative;
margin-right: 20px;
}
main nav {
display: flex;
height: 50px;
align-items: center;
}
main nav a,main nav span {
background: #95a5a6;
margin-right: 0px;
padding: 10px 20px;
border: solid 1px #333;
color: #fff;
text-decoration: none;
}
main nav a:first-of-type,
main nav span:first-of-type{
background: #e67e22;
}
section {
height: 200px;
width: 100%;
background: #f1c40f;
position: absolute;
font-size: 5em;
/* display: none; */
}
.hd-tab section:first-of-type {
display: block;
}
section:nth-child(even) {
background: #27ae60;
}
</style>
<body>
<main class="tab1">
<nav>
<a href="javascript:;">后盾人</a>
<a href="javascript:;">hdcms</a>
</nav>
<section>1</section>
<section>2</section>
</main>
<main class="tab2">
<nav>
<span href="javascript:;">后盾人</span>
<span href="javascript:;">hdcms</span>
</nav>
<section>1</section>
<section>2</section>
</main>
</body>
<script>
function extend(sub,sup) { //继承原型的工厂
sub.prototype = Object.create(sup.prototype);
sub.prototype.constructor = sub;
}
function Animation() { //变化
}
Animation.prototype.show=function () { //显示
this.style.display="block";
};
Animation.prototype.hide=function () { //隐藏
this.style.display="none";
};
Animation.prototype.background=function (color ) { //改变背景颜色
this.style.backgroundColor=color;
};
function Tab(args) {
args = Object.assign(
{el:null, link:"a", section:"section", callback:null},
args
);
this.tab = document.querySelector(args["el"]);
this.links = this.tab.querySelectorAll(args["link"]);
this.sections = this.tab.querySelectorAll(args["section"]);
// console.log(this.sections);
this.callback = args["callback"];
}
extend(Tab,Animation);
Tab.prototype.run=function () {
this.bindEvent();
this.reset();
this.action(0);
}
Tab.prototype.bindEvent=function () {
this.links.forEach((el, i) =>{
el.addEventListener("click", () =>{
this.reset();
this.action(i); //i是下标
if(this.callback) this.callback();
})
});
}
Tab.prototype.action=function (i) {
this.background.call(this.links[i], "#e67e22");
this.show.call(this.sections[i]);
}
Tab.prototype.reset=function () {
this.links.forEach((el,i)=>{
this.background.call(this.links[i], "#95a5a6");
this.hide.call(this.sections[i]);
})
}
new Tab({
el: ".tab1",
callback() {
console.log("houdurnen.com");
}
}).run();
new Tab({el: ".tab2", link: "span", callback: function () {
console.log("刘兴加");
}}).run();
</script>
</html>