let和const

应用 var 带来的问题

var 净化全局变量

var a=1;console.log(window.a)

var 会使变量晋升

console.log(a) // undefinedvar 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、constructotfunction 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=>s2function diff(){    return [...s1].filter(item=>!s2.has(item));}

Map

Mapkey 值,不能反复,WeakMapkey 必须是对象类型

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

对象自带的 gettersetter:

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")

箭头函数

箭头函数没有 thisarguments

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;}