每每有空 看一看;敲一敲
1.数据劫持 Object.defineProperty和proxy
/**
* proxy Object.defineProperty
*/
//proxy 代理 对比 object.defineProperty
handler = {
set(target, key, value) {
console.log(key, "set");
target[key] = value;
return true;
},
};
var target = {};
var proxydata = new Proxy(target, handler);
/**
* 数据劫持 defineProperty
*/
function definePropertydata() {
let _val = "";
let _nameList = [];
Object.defineProperties(this, {
aname: {
get() {
return _val;
},
set(newVal) {
_val = newVal;
_nameList.push(_val);
},
},
bname: {
get() {
return _val;
},
set(newVal) {
_val = newVal;
_nameList.push(_val);
},
},
});
this.getNameList = function() {
return _nameList;
};
}
var backDefineData = new definePropertydata();
backDefineData.aname = "test get aname";
backDefineData.bname = "test get bname";
console.log(backDefineData.getNameList());
2.原型 原型链
/**
* 原型 原型链
*/
//函数 两个价值 1.实现具体 2.作为对象
//函数 既是函数也是对象 既有 prototype 也有__proto__
//原型与隐式原型的关系
//每一个构造函数都有prototype原型属性,通过构造函数创建出来的对象都继承自该原型属性。
//对象.__ptoto__ == 构造器.prototype
//对象的隐式原型等于 创建这个对象的构造器的原型
//经典题目
function Func() {
this.name = 11;
} //既有 prototype 也有__proto__
//每個对象都有__proto__
Func.prototype.func = function() {
// console.log('222');
};
var nfunc = new Func();
nfunc.func();
nfunc.name;
console.log(nfunc.__proto__ == Func.prototype);
//nfunc.__proto__ == Func.prototype
//Func.prototype__proto__ == Object.prototype;
//Object.prototype.__proto__ == null
function Munc(name, sex) {
this.name = name;
this.sex = sex;
}
Munc.prototype.hellword = function() {
console.log(this.name, this.sex);
};
var m_func = new Munc("111", "man");
m_func.hellword();
3.实现 一个new功能
/**
*
* 实现 一个new功能
*/
///A.实现一个new 1.新建一个空对象 2 对象的__proto__ == 调用者的prototype 3.改变指向 apply
//备注:函数上的方法 是挂载在__proto__上的
//第一步 空位对象
//第二步 通过原型链 让 空对象的__proto__ == 传入对象的prototype 目的是空对象可以调用到传入对象的方法
//第三步 通过apply或call 改变this指向 目的是 让空对象可以访问传入对象的属性值
function _new() {
var _object = {};
let constructor = [].shift.apply(arguments); //arguments是类数组对象 需要转换 或者用Array.prototype
_object.__proto__ = constructor.prototype;
let resback = constructor.apply(_object, arguments);
return resback;
}
//B 第二种 更简洁的 利用 Object.create 创建一个新对象
function _new() {
var _object = {};
let nModel = Array.prototype.shift.call(arguments);
_object = Object.create(nModel);
let res = nModel.apply(_object, arguments);
return res;
}
4.实现一个 call 功能
/**
* 实现一个 call 功能
*/
Function.prototype._call = function(object, ...arg) {
object.fn = this;
let backfn = object.fn(...arg);
delete object.fn;
return backfn;
};
function f(name, age) {
return this.value + name + age;
}
let newModel = { value: 100 };
console.log(f._call(newModel, 1, 2));
//call bind apply 区别
//apply 和 call 基本类似,他们的区别只是传入的参数不同
//apply 参数 数组或类数组
//bind()方法创建一个新的函数, 当被调用时,将其this关键字设置为提供的值,在调用新函数时,在任何提供之前提供一个给定的参数序列。
//bind 是创建一个新的函数,我们必须要手动去调用
5.valueOf 的使用
//valueOf 的使用 (当值 进行 == <> + - */ 时 会自动调用)
//同理 toString 一样 优先级 valueOf ; toString 偏向于显示 valueOf偏向于运算
let age = {
i: 1,
valueOf: () => {
age.i++;
},
};
if (age == 1) {
console.log("判断时候自动调用了!" + age);
}
6.reduce 计算最大和最小值
//reduce 计算最大和最小值
let max = datalist.reduce((currentdata, item) => {
return currentdata.count >= item.count ? currentdata.count : item.count;
});
let min = datalist.reduce((currentdata, item) => {
return currentdata.count <= item.count ? currentdata.count : item.count;
});
7.数组或类数组 去重并合并 关键字 filter concat
let a = [
{ name: "aa", sex: "bb" },
{ name: "dd", sex: "bb" },
{ name: "ee", sex: "bb" },
{ name: "ff", sex: "bb" },
];
let b = [
{ name: "aa", sex: "bb" },
{ name: "bb", sex: "bb" },
{ name: "cc", sex: "bb" },
];
let find_data = a.map((item) => item.name);
let new_data = b.filter((v) => !find_data.includes(v.name));
let result = a.concat(new_data);
console.log(result);
8.正则表达式
//正则表达式
// /xxxx/
// /xxx/i 不区分大小写
// /xxx/g 全局搜索
// /xxx/m 多行搜索
// [] 表达式 [A-Z] A到Z
// [^] 取反
//元字符 \w ===[0-9A-z] \d===[0-9]
//n+ {1,正无穷} demo:'abcd' => ['abcd']
//--贪婪模式
//n* {0,正无穷} demo:'abcd' => ['abcd']['']
//n? {0或1} demo:'abcd' => ['a']['b']['c']['d']['']
//n{1,2} demo:'abcd' => ['ab']['cd']
//^n n开头
//n$ n结尾
//?=n 匹配后面紧跟n的
//?!n 匹配不是紧跟着n的
//子表达式 () /(a)(b)/ (a)第一个表达式 (b)第二个表达式
//反向引用 \x x表示第几个表达式 \1 /(a)\1\1\1/ 表示取第一个表达式 需要几次就写几次
//子表达式具有记忆功能 会按照子表达的规则去匹配
9.递归方法
function formatRouterTree(datalist) {
let parentRouter = datalist.filter((pi) => pi.pid == 0);
let childrenRoter = datalist.filter((ci) => ci.pid != 0);
dataTreelist(parentRouter, childrenRoter);
//递归方法
function dataTreelist(parentRouter, childrenRoter) {
parentRouter.map((p) => {
childrenRoter.map((c, i) => {
if (c.pid == p.id) {
let _c = JSON.parse(JSON.stringify(childrenRoter));
_c.splice(i, 1);
dataTreelist([c], _c);
if (p.children) {
p.children.push(c);
} else {
p.children = [c];
}
}
});
});
}
return parentRouter;
}
10.模拟实现VUE 数据双向绑定
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<div id="app">
<div>
<input type="text" v-wc="name" placeholder="姓名" />
<input type="text" v-wc="age" placeholder="年龄" />
<input type="text" v-wc="email" placeholder="email" />
<input type="text" v-wc="tel" placeholder="tel" />
</div>
<div>
<p>姓名:<span>{{name}}</span> </p>
<p>年龄:<span>{{age}}</span></p>
<p>email:<span>{{email}}</span></p>
<p>tel:<span>{{tel}}</span></p>
</div>
</div>
</body>
</html>
<script type="text/javascript" src="./src/libs/MVVM.js"></script>
<script>
const app = new MVVM('#app',{
name:'wzt',
age:'18',
email:'123',
tel:'44',
});
</script>
class MVVM {
constructor(el, data) {
this.el = document.querySelector(el);
this._data = data;
this.domdata = {};
this.init();
}
init() {
this.initData();
this.initDom();
}
initDom() {
this.bindInput(this.el);
this.bindDom(this.el);
}
//1.实现数据相应 (数据劫持) definePrototy || proxy
initData() {
const _this = this;
this.data = {};
for (let key in this._data) {
console.log(key);
Object.defineProperty(this.data, key, {
get() {
console.log(1111);
return _this._data[key];
},
set(newVal) {
console.log(222);
//绑定值到元素上
_this.domdata[key].innerHTML = newVal;
_this._data[key] = newVal;
},
});
}
}
//2.捕获 input 绑定事件 keyup 值 改变数据 (找到指令 如 v-model)
bindInput(el) {
const _allinputs = el.querySelectorAll("input");
_allinputs.forEach((input) => {
const _findmodel = input.getAttribute("v-wc"); //找到属性值
if (_findmodel) {
//绑定事件
input.addEventListener(
"keyup",
this.handleInput.bind(this, _findmodel, input)
);
}
});
}
handleInput(key, input) {
const _value = input.value;
this.data[key] = _value;
}
//3.绑定改变的值到页面p (找到 {{}} )
bindDom(el) {
const childnodes = el.childNodes;
childnodes.forEach((item) => {
if (item.nodeType == "3") {
const _value = item.nodeValue;
if (_value.trim().length) {
//正则判断 是否有{{}}
let _valid = /\{\{(.+?)\}\}/.test(_value);
if (_valid) {
//找到KEY
let _key = _value.match(/\{\{(.+?)\}\}/)[1].trim();
this.domdata[_key] = item.parentNode;
//找到节点 给节点赋值
item.parentNode.innerText = this._data[_key] || "";
}
}
}
item.childNodes && this.bindDom(item);
});
}
}
11. js继承 ES5 和 ES6 区别
/**
* @description 继承 ES5 和 ES6 区别
* @auth wzt
* @version 1.0
*/
//继承 ES5 (原型链,构造函数,组合继承)
function Student(name, age) {
this.name = name;
this.age = age;
}
Student.prototype.Setcourse = function() {
console.log("aaa");
};
function Flamly(name, age, sex, height) {
Student.call(this, name, age);
this.sex = sex;
this.height = height;
}
Flamly.prototype = Object.create(Student);
Flamly.prototype.constructor = Student;
var s1 = new Flamly("xx", "11");
//继承 ES6
class Person {
//调用类的构造方法
constructor(name, age) {
this.name = name;
this.age = age;
}
//定义一般的方法
showName() {
console.log("调用父类的方法");
console.log(this.name, this.age);
}
}
let p1 = new Person("kobe", 39);
console.log(p1);
//定义一个子类
class Student extends Person {
constructor(name, age, salary) {
super(name, age); //通过super调用父类的构造方法
this.salary = salary;
}
showName() {
//在子类自身定义方法
console.log("调用子类的方法");
console.log(this.name, this.age, this.salary);
}
}
let s1 = new Student("wade", 38, 1000000000);
console.log(s1);
s1.showName();