let和const
使用 var 带来的问题
var 污染全局变量
var a=1;
console.log(window.a)
var 会使变量提升
console.log(a) // undefined
var a=1;
var 可以被重复声明
var a=1;
var a=2;
var a=3;
var 作用域问题
全局作用域
{
var a=1;
}
console.log(a) // 1
{
let b=2;
}
console.log(b) // b is not defined
函数作用域
for(var i=0;i<3;i++){
setTimeout(()=>console.log(i),0) // 3,3,3
}
for(let i=0;i<3;i++){
setTimeout(()=>console.log(i),0) // 0,1,2
}
const 常量
const
指向地址不变
展开运算符
合并对象或数组
合并数组
let a=[0,1];
let b=[2,3];
console.log([...a,...b]) //[0, 1, 2, 3]
合并对象
合并对象要区分是深拷贝还是浅拷贝,展开运算符只拷贝对象一层,属于浅拷贝
let team={name:"Lakers",location:{city:"Los Angeles"}};
let player=["LeBron","Davis"];
let kuzma = {age:25};
let coach = {name:"Frank Vogel",age:47};
let Lakers = {
...team,
...coach,
player:[...player,kuzma]
}
team.name="change"; // Lakers 修改失败,浅拷贝
team.location.city = "change"; // Lakers 修改成功,引用地址未变
console.log(Lakers)
实现深拷贝
1、继续展开
let Lakers = {
team:{
...team,
location:{...team.location}
},
...coach,
player:[...player,kuzma]
}
2、对象转字符串再转对象,这种方式有个缺陷,会忽略掉值为undefined
的属性
Lakers = JSON.parse(JSON.stringify(Lakers))
3、实现深拷贝方法
// 判断类型:typeof、instanceof、Object.prototype.toString.call、constructot
function deepClone(obj){
// 不是对象直接返回
if(obj == null) return obj;
if(obj instanceof Date) return new Date(obj);
if(obj instanceof RegExp) return new RegExp(obj);
if(typeof obj !== "object") return obj;
// 可能是数组或对象
let cloneObj = new obj.constructor;
for(let key in obj){
if(obj.hasOwnProperty(key)){
// 递归赋值
cloneObj[key] = deepClone(obj[key]);
}
}
return cloneObj
}
Set 和 Map
Set
let s1 = new Set([0,1,2,0,2]);
let s2 = new Set([2,3,3,4,5]);
// 并集
function union(){
let merge = [...s1,...s2];
return [...new Set(merge)]
}
// 交集
function intersection(){
return [...s1].filter(item=>s2.has(item));
}
// 差集 s1=>s2
function diff(){
return [...s1].filter(item=>!s2.has(item));
}
Map
Map
有 key
值,不能重复,WeakMap
的 key
必须是对象类型
let wm=new WeakMap();
let obj = {name:"124"};
wm.set(obj,"test");
obj = null;
console.log(wm) // 清空obj,这个空间仍然存在m
/* WeakMap
* [[Entries]]
* 0: {{name: "124"} => "test"}
*/
利用WeakMap
优化 深拷贝函数:
function deepClone(obj,hash = new WeakMap()){
if(obj == null) return obj;
if(obj instanceof Date) return new Date(obj);
if(obj instanceof RegExp) return new RegExp(obj);
if(typeof obj !== "object") return obj;
// 如果是对象并存在weakMap中,说明拷贝的对象已经存在了,直接返回
if(hash.has(obj)) return hash.get(obj);
let cloneObj = new obj.constructor;
// 保存拷贝的对象到WeakMap中
hash.set(obj,cloneObj);
for(let key in obj){
if(obj.hasOwnProperty(key)){
cloneObj[key] = deepClone(obj[key],hash);
}
}
return cloneObj
}
Object.defineProperty
对象自带的 getter
和 setter
:
let obj = {
value:"124",
get name(){
console.log("get")
return this.value
},
set name(val){
console.log("set")
this.value = val;
}
}
console.log(obj.name)
obj.name="test";
console.log(obj.name)
利用 Object.defineProperty
实现数据劫持
let update = () => console.log("update");
let team = {
name: "Lakers",
player:["lbj","ad"],
location: {
city: "Los Angeles"
}
};
observer(team);
function observer(obj) {
if(typeof obj !== "object") return obj;
for(let key in obj) {
defineReactive(obj, key, obj[key]);
}
}
function defineReactive(obj, key, value) {
observer(value);
Object.defineProperty(obj,key,{
get(){
return value
},
set(newVal){
if(newVal === value) return;
update();
observer(newVal); // 新值也有可能是对象
value = newVal
}
})
}
// 数组操作无法劫持,重写无法劫持的数组方法
const Methods = ["push","pop","shift","unshift","slice","sort","reverse"];
Methods.forEach(method=>{
// 面向切面开发,装饰器
const oldMethod = Array.prototype[method];
Array.prototype[method] = function(){
update();
oldMethod.apply(this,arguments)
}
});
team.name="la";
team.location.city = "change";
team.player.push("kz")
箭头函数
箭头函数没有 this
和 arguments
Proxy
- Object.defineProperty 劫持不到数组的更新(push、pop、shift、unshift)
- Proxy 可以监测到数组和对象的变化
- Proxy 监测数组变化时,要注意数组长度的变化也会被监测到,这时手动改变数组会出问题
let update = ()=>console.log("update");
let arr = [1,2,3];
// Proxy 可以监测到数组和对象的变化
// 数组的变化会先改变数组的内容,还会改变数组的长度
let proxy = new Proxy(arr,{
set(target,key,value){
// 不要手动操作数组,因为数组变化时,可能调用push或pop改变数组长度,这时key值会出问题
if(key == "length") return true;
update();
return Reflect.set(target,key,value);
},
get(target,key){
return Reflect.get(target,key);
}
})
proxy.push("4");
console.log(proxy)
数组常用方法
- es5 forEach reduce map filter some every
- es6 find findIndex
- es7 includes
reduce 常见用法
求和
// 购物车
let cart = [
{price:10,count:2},
{price:20,count:3},
{price:19.9,count:2},
{price:14.5,count:1}
];
// 求购物车总价格
let totalPrice = cart.reduce(
(total,item)=>total+item.price*item.count,0
);
合并数据
let keys = ["name","age"];
let value = ["kobe",18];
let result = keys.reduce(
(obj,key,index)=>{
obj[key]=value[index]
return obj;
},{}
);
compose 方法
function sum(a,b) {
return a+b
};
function toUpper(str){
return str.toUpperCase();
}
function log(target){
console.log(target)
}
compose(sum,toUpper,log)("chen","wl");
function compose(...middlears){
//return middlears.reduce((a,b)=>(...args)=>b(a(...args)))
return (...args)=>{
let fn = middlears.shift();
middlears.reduce((a,b)=>{
return b(a)
},fn(...args));
}
}
reduce
简单实现
Array.prototype.reduce = function(fn,prev){
let target = deepCopy(this);
let total = prev || target.shift();
target.forEach((next,i)=>{
total = fn(total,next,i,target);
});
return total;
}
let result = [1,2,3,4].reduce((a,b)=>a+b);
console.log(result)
function deepCopy(obj){
if(obj == null) return obj;
if(typeof obj !== "object") return obj;
let newObj = new obj.constructor;
for(let key in obj){
newObj[key] = deepCopy(obj[key])
}
return newObj;
}