1、let const(新增)
es6 -> es5 babel
- 声明的变量默认声明到全局上,全局作用域 函数作用域 {} 作用域+ let 实现一个作用域
- 用var 声明的变量会导致变量提升 var function import。用let声明的变量会绑定到当前作用域 暂存死区
- var a = 1 var a = 2; 使用let 可以保证我的代码命名不重复
- var 声明的变量可以更改 var a = 1 a =100。
- 自执行函数可以解决作用域问题
- js 事件 不要用var
for (let i = 0; i < 10; i++) {
setTimeout(()=>{
console.log(i)
}); // 4ms
};
2、解构赋值 ... 集合 Set
解构的方式都是根据key来实现
// 解构的方式都是根据key来实现
let [,age] = ['姓名','年龄'];
console.log(age);
// 用:号来重新命名 = 可以用来赋值默认值
let {name,age:age1,address="CN"} = {name:'xx',age:10};
console.log(name,age1,address);
// 剩余运算符 只能用在最后一项
let [,...args] = ['xx',10,'CN']; // slice
console.log(args);
// 对象的剩余运算符
let {name,...args} = {name:'珠峰',age:10};
console.log(args);
// (set + map) set 和map 是es6中新的数据类型 不能放重复的
let set = new Set([1,2,3,3,2,1]);
console.log(set); // 没有key属性
set.add(4);
// set.clear()// 清除
// set.delete(); // 删除某一项
console.log(set.entries()) // Object.entries Object.keys Object.values
// Symbol.iterator
set.forEach(item=>{
console.log(item);
})
console.log(set.has(1))
// union
let a1 = [1,2,3];
let a2 = [4,5,6,1,2,3];
// let s1 = new Set([...a1,...a2]);
// console.log([...s1]);
// 数组的交集 和 差集 has来实现 set方法只有forEach方法
let s1 = new Set([...a1]); // [1,2,3]
let s2 = new Set([...a2]); // [1,2,3]
let a3 = [...s2].filter((item=>{ // 返回的是一个新的数组
return !s1.has(item); // map是映射一个新的数组 但是不会比以前的项少
}));
console.log(a3);
// map 和set 用法基本一致
3、for of 字符串遍历
let str = "hello";
//1.for遍历
for (let i = 0; i < str.length; i++) {
console.log(i, str[i]); //i 索引 数值类型
}
//2.数组->for->for in
let arr = [1, 2, 3];
for (let i in arr) {
console.log(i, arr[i]); //i 索引 字符串类型
}
//3.for... of
for(let i of str){
console.log(i); //数据
}
//4.解构
let [a, b, c, d ,e] = str;
console.log(a, b, c, d ,e);
4、深拷贝
Q:怎么判断数据的类型?
typeof object Array
Object.prototype.toString.call()
instanceof 可以判断类型 判断是谁的实例
constructor 构造函数
递归实现深拷贝
let school = {
name: "珠峰",
age: 10,
a: { b: 2 },
fn: () => {},
c: undefined,
reg: /\d+/
};
const deepClone = (value ,hash = new WeakMap) => {
if(value == null) return value; // 排除掉null 和undefine 的情况
if(typeof value !== 'object') return value; // 这里包含了函数类型
if(value instanceof RegExp) return new RegExp(value);
if(value instanceof Date) return new Date(value);
// .....
// 拷贝的人可能是一个对象 或者是一个数组 (循环) for in
let instance = new value.constructor; // 根据当前属性构造一个新的实例
if(hash.has(value)){ // 先去hash中查看一下是否存在过 ,如果存在就把以前拷贝的返回去
return hash.get(value); // 返回已经拷贝的结果
}
hash.set(value,instance);// 没放过就放进去
// 用一个对象来记忆
for(let key in value){ // 一层
if(value.hasOwnProperty(key)){ // 将hash 继续向下传递 保证这次拷贝能拿到以前拷贝的结果
instance[key] = deepClone(value[key],hash); // 产生的就是一个新的拷贝后的结果
}// 过滤掉原型链上的属性
}
return instance
};
let obj = {a:1};
obj.b = obj; // 如果obj 已经被拷贝了一次 那下次 在用到obj的时候 直接返回就好了 不需要再次拷贝了
console.log(deepClone(obj));
JSON.parse(JSON.stringify(a)) 转换也可以实现深拷贝,但是数据中有数值类型可能会有精度缺失的问题。不能拷贝正则,Date,方法函数等。
浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。但深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
5、defineProperty
用在对象上设新属性,在ES6中,由于 Symbol类型的特殊性,用Symbol类型的值来做对象的key与常规的定义或修改不同,而Object.defineProperty
是定义key为Symbol的属性的方法之一。
let obj = {}
let val = '';
Object.defineProperty(obj,'a',{
configurable:true, // 是否可删除
// writable:true, // 是否可写,
enumerable:true, // for in 原型上的方法
get(){
return val
},
set(value){
val = value;
}
// 默认设置的值是不可枚举的
})
delete obj.a
console.log(obj);
6、Proxy代理
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
// 代理 我们可以创造一个代理 帮我们干某些事
let obj = {
a:{a:2}
}
let handler = { // 只能代理当前这个对象 1层
get(target,key){ // 有13中属性 symbol 11种
// return target[key]
if(typeof target[key] === 'object'){
return new Proxy(target[key],handler); // 如果是对象 就返回这个对象的代理
}
return Reflect.get(target,key);
},
set(target,key,value){ // 反射属性
// target[key] = value;
if(key === 'length') return true;
console.log('update');
return Reflect.set(target,key,value);
}
}
let proxy = new Proxy(obj,handler)
proxy.a.a = 100
console.log(obj.a.a);
// 支持数组 可以直接更改数组 达到拦截的目的
7、Reflect
Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与proxy handlers 的方法相同。Reflect
不是一个函数对象,因此它是不可构造的。
- get/set
- has
- defineProperty
- getOwnPropertyDescriptor
- ownKeys
- setPrototypeOf, getPrototypeOf
-
函数的apply方法
Q: bind、apply、call区别
bind传参“~”,call、apply传参是数组形式。第一个是改变this指向。
// 2) has
// 老的写法
console.log('a' in {a:1});
// 新的写法
console.log(Reflect.has({a:1},'a'));
// 3)defineProperty
const obj = {a:1}
// Object.freeze(obj); // 这个属性就能不能配置了 冻结freeze
let flag = Reflect.defineProperty(obj,'a',{
value:100
})
console.log(flag);
8、Symbol
独一无二,用作常量
hasInstance、 toPrimitive、 toStringTag、 species、 unscopables、 isConcatSpreadable
9、class类
es5中没有类 用构造函数来模拟类
原型链
__proto__ 指向所属类的原型
prototype 所有类都有一个prototype属性
constructor prototype.constructor 每个类的原型上都有这个属性
微任务: promise.then ,MutationObserver,
宏任务:script ,ajax , 事件,requestFrameAnimation, setTimeout ,setInterval ,setImmediate (ie下),MessageChannel ,UI rendering。