es6笔记

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

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