let myName = "haonan";
function test(){
console.log(myName);
let myName = "nan";
}
test(); // 报错
打印下面重新定义了 myName,则存在暂存性死区,打印则会报错,如果打印下方没有重新定义,则不会报错值为初始定义的 myName
Number.isFinite():是否是数值
let num1 = Number.isFinite(100) //true
let num2 = Number.isFinite(100/0) //false
let num3 = Number.isFinite("Infinity") // false
let num4 = Number.isFinite("100") //false
Number.isNaN():是否为NaN
let num1 = Number.isNaN(100) // false
let num2 = Number.isNaN(NaN) //true
let num3 = Number.isNaN("kerwin") //false
let num4 = Number.isNaN("100") // false
两个方法只对数值有效,isFinite()对于非数值一律返回false,isNaN()只对NaN返回true,其它一律为false
Number.isInteger():判断数值是否为整数
let num1 = Number.isInteger(100) // true
let num2 = Number.isInteger(100.0) //true
let num3 = Number.isInteger("kerwin") //false
let num4 = Number.isInteger("100") // false
EPSILON:表示 1 与大于 1 的最小浮点数之间的差【精度失真】
function isEqual(a,b){
return Math.abs(a-b) < Number.EPSILON
}
console.log(isEqual(0.1 + 0.2,0.3)); // true
console.log(0.1 + 0.2 === 0.3); // false
Math.trunc():将小数部分抹掉,返回一个整数
console.log(Math.trunc(1.2)) // 1
console.log(Math.trunc(1.9)) // 1
console.log(Math.trunc(-1.8)) // -1
console.log(Math.trunc(-1.2)) // -1
Math.sign():判断是正数、负数、还是零。对于非数值,会先将其转换为数值
Math.sign(-100) // -1
Math.sign(100) // +1
Math.sign(0) // +0
Math.sign(-0) // -0
Math.sign("haonan") // NaN
数组.find(function(item){ }) | 数组.findIndex(...)
let arr = [11,12,13,14,15];
let res1 = arr.find(item => return item > 13);
let res2 = arr.findIndex(item => return item > 13);
console.log(res1); // 14
console.log(res2); // 3
数组.fill(替换内容,起始下标,结束下标)【包前不包后】:替换内容
let arr1 = new Array(3).fill("haonan");
let arr2 = ["a","b","c"].fill("haonan",1,2);
console.log(arr1); // ["haonan","haonan","haonan"]
console.log(arr2); // ["a","haonan","c"]
数组.flatMap(...):按照一个可指定的深度递归遍历数组,并将所有元素与遍历到的子数组中的元素合并为一个新数组
var obj = [
{
name: "A",
list: ["洛阳","郑州","许昌"]
},
{
name: "B",
list: ["北京","上海","深圳"]
}
]
console.log(obj.flatMap(item => item.list));
对象简写
let name = "haonan"
let obj = {
name,
// 方法简写
test1(){
},
test2(){
}
}
console.log(obj); // name : "haonan"
属性名表达式
let name = "haonan";
let obj = {
name,
[name+"one"](){
},
[name+"two"](){
}
}
Object.is():判断两个值是否是相同的值
console.log(NaN === NaN); // false
console.log(+0 === -0); // true
console.log(Object.is(NaN,NaN)); // true
console.log(Object.is(+0,-0)); // false
表示独一无二的值,它属于 JavaScript 语言的原生数据类型之一
基本使用
let s1 = Symbol(); // 生成了一个symbol类型数据
let s2 = Symbol();
console.log(s1 === s2); // false
console.log(s1.toString()+"aaa");
if(s1){
console.log("执行");
}
使用Symbol作为对象属性名
```js let name = Symbol(); let age = Symbol(); var obj = {
[name]: "haonan",
[age]: 22
}
- Symbol()函数可以接收一个字符串作为参数,表示对 Symbol 实例的描述。这主要是为了在控制台显示,比较容易和普通对象属性的区分
```js
let name = Symbol("name");
let age = Symbol("age");
var obj = {
[name]: "haonan",
[age]: 22
}
console.log(obj);
遍历问题【Symbol作为属性不能被for in 遍历】
```js let keys = {
name: Symbol("name");
age: Symbol("age");
} var obj = {
[keys.name]: "haonan",
[keys.age]: 22,
a:1
} // 遍历 Reflect.ownKeys(obj).forEach(item => { console.log(item,obj[item]); })
- 使用场景:用来匹配switch拥有更高的可读性
```js
const VIDEO = Symbol();
const AUDIO = Symbol();
const IMAGE = Symbol();
function play(type){
switch(type){
case VIDEO:
console.log("音频播放");
break;
case AUDIO:
console.log("视频播放");
break;
case IMAGE:
console.log("图片展示");
break;
}
}
play(IMAGE)
作用
let arr = ["haonan","lize","wusai"]
for(let i of arr){
console.log(i)
}
Iterator遍历过程
// 1.创建一个指针对象,指向当前数据结构的起始位置,也就是说,遍历器对象本质上,就是一个只针对象
// 2.第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员
// 3.第二次调用指针对象的next方法,指针就指向数据结构的第二个成员
// 4.不断调用指针对象的next方法,直到它指向数据结构的结束位置
let i = arr[Symbol.iterator]();
console.log(i.next()); // Object { value: "haonan", done: false }
console.log(i.next()); // Object { value: "lize", done: false }
console.log(i.next()); // Object { value: "wusai", done: false }
console.log(i.next()); // Object { value: undefined, done: true }
默认的 Iterator 接口部署在数据结构的 Symbol.iterator 属性,或者说,一个数据结构只要具有 Symbol.iterator 属性,就可以认为是 “可遍历的”。Symbol.iterator 属性本身是一个函数,就是当前数据结构默认的遍历器生成函数,执行则会返回一个遍历器
默认具备 Iterator 接口的数据结构:
对于对象进行 for of遍历【埋上迭代器】
```js let obj = {
0: "haonan",
1: "wusai",
2: "lize",
length: 3, // 如果没有长度 则不会有预期效果,因为不知道什么时候结束
[Symbol.iterator]: Array.prototype[Symbol.iterator]
} for(let i of obj){ console.log(i) }
- 对对象进行 for of遍历【手写】
```js
let obj2 = {
data: ["haonan","wusai","lize"],
[Symbol.iterator](){
let index = 0;
return {
// 使用箭头函数,否则this指向不对
next: () => {
value: this.data[index++],
done:index === (this.data.length+1) ? true:false
}
}
}
}
for(let i of obj2){
console.log(obj2);
}
类似数组,但成员都是唯一的,没有重复的值
使用
let s1 = new Set([1,2,3,2,3,2])
console.log(s1); // 1,2,3
实例属性和方法
遍历
复杂数据结构去重
function distinct(arr){
let res = new Set();
return arr.filter(item => {
let i = JSON.stringify(item);
if(res.has(i)){
return false;
}else{
res.add(i);
return true;
}
})
}
let arr = [1,2,2,3,"data",{name:"haonan"},[1,2],[3,4],[1,2],{name:"haonan"}];
console.log(distinct(arr));
类似对象,建可以是各种类型包括对象
使用
let m1 = new Map();
m1.set("name","haonan");
m1.set({a:1},"洛阳");
console.log(m1);
let m2 = new Map([
["name","haonan"],
[{a:1},"洛阳"]
])
console.log(m2);
实例的属性和方法
遍历
let m1 = new Map();
m1.set("name","haonan");
m1.set("address","洛阳");
// 解构赋值
for(let [index,item] of m1){
console.log(index,item);
}
// of entries和上面一样效果
for(let [index,item] of m1.entries()){
console.log(index,item);
}
m1.forEach((index,item) => {
console.log(index,item);
})
作用
没有proxy原始想去拦截的写法
<body>
<div id="box">
</div>
<script>
let obj = {};
Object.defineProperty(obj,"data",{
get(){
console.log("get");
return box.innerHTML;
}
set(value){
console.log("set",value);
box.innerHTML = value;
}
})
console.log(obj)
</script>
</body>
【问题:每次只能拦截一个属性,想要全部拦截,需要遍历较为繁琐】
proxy写法
<body>
<div id="box">
</div>
<script>
let obj = {};
let proxy = new proxy(obj,{
// target为obj对象,key为调用的属性名或方法名
get(target,key){
console.log("get",target[key]);
return target[key];
},
// key为属性名 value 为属性值
set(target,key,value){
if(key === "data"){
box.innerHTML = value
}
target[key] = value
},
// 默认存在的一个方法 用于 in 的判断
has(target,key){
return key in target;
}
})
obj.name = "haonan";
// 判断该属性名是否存在该对象当中
console.log("name" in obj);
</script>
</body>
代理Set【this指向问题】
let s = new Set();
const proxy = new proxy(s,{
get(target,key){
// 如果调用的是方法,比如add,则会出现问题,需要改变this指向
const value = target[key]
if(value instanceof Function){
console.log(`访问了${value}方法`);
// 此处不能使用 call 或者 apply 因为这两个改变this指向时会进行调用函数
return value.bind(target);
}
return value;
},
set(target,key,value){
target[key] = value;
}
})
可以用于获取目标对象的行为,它与 Object 类似,但更易读,为操作对象提供了一种更优雅的方式,它的方法与Proxy是对应的。Reflect代替Object的某些方法,为后续对于获取目标对象的一系列操作都放在Reflect对象上面
代替Object的某些方法
const obj = {
};
Reflect.defineProperty(obj,"name",{
value: "haonan",
// 不可再次修改
writable: false,
// 不可以被配置该属性
configurable: false
})
修改某些Object的返回值结果
// 老写法
try{
Object.defineProperty(target,property,attributes);
// success
}catch(e){
// fail
}
// 新写法
if(Reflect.defineProperty(target,property,attributes)){
// success
}else{
// fail
}
命令式变为函数行为
const obj = {
name: "haonan"
};
// 老写法
console.log("name" in obj); // true
// 新写法
console.log(Refulect.has(obj,"name")); // true
// 老写法
delete obj.name
// 新写法
Reflect.deleteProperty(obj,"name");
Reflect.set(obj,"age",100);
console.log(Refulect.get(obj,"name"));
配合Proxy【修改Proxy对于Set的代理】
let s = new Set();
const proxy = new proxy(s,{
get(target,key){
// 如果调用的是方法,比如add,则会出现问题,需要改变this指向
const value = Reflect.get(target,key);
if(value instanceof Function){
console.log(`访问了${value}方法`);
// 此处不能使用 call 或者 apply 因为这两个改变this指向时会进行调用函数
return value.bind(target);
}
return value;
},
set(){
return Reflect.set(...arguments);
}
})
Reflect对于代理数组的问题解决
let arr = [1,2,3];
let proxy = new Proxy(arr,{
get(target,key){
console.log("get",key);
return Reflect.get(...arguments);
},
set(target,key,value){
return Reflect.set(...arguments);
}
})
proxy.push(4);
// 打印内容
// get push (寻找 proxy.push 方法)
// get length (获取当前的 length)
// set 3 4 (设置 proxy[3] = 4)
// set length 4 (设置proxy.length = 4)
是异步编程的一种解决方案,比传统的解决方案回调函数,更合理强大。ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象
作用
回调地狱
ajax({
url: "第一个请求",
success(res){
// 发送第二个
ajax({
url: "第二个请求",
data: {a:res.a,b:res.b},
success(res2){
// 发送第三个
ajax({
url: "第三个请求",
data:{a:res2.a,b:res2.b},
success(res3){
...;
}
})
}
})
}
})
这样的嵌套称为回调地狱,导致没有维护的可能
Promise使用
let pro = new Promise(function(resolve,reject){
// 执行函数
setTimeout(() => {
resolve(1000);
//reject("no");
},1000)
})
// pro.then(() => {
// console.log("奖金");
// }).() => {
// console.log("没有");
// }
pro.then((res) => {
console.log("奖金",res);
}).catch((err) => {
console.log("没有",err);
})
Promise 对象的状态
变化途径只有两种:从 未完成 —— 成功,从 未完成 到——失败
封装ajax【更好的理解axios】
function ajax(url){
return new Promise((resolve,reject) => {
let xhr = new XMLHttpRequest();
xhr.open("get",url,true);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.status >= 200 && xhr.status < 300){
resolve(JSON.parse(xhr.responseText));
}else{
reject(xhr.responseText);
}
}
})
}
ajax("./1.json").then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
链式多then
let pro = new Promise(function(resolve,reject){
// 执行函数
setTimeout(() => {
resolve(1000);
//reject("no");
},1000)
})
pro.then((res) => {
console.log("奖金",res);
// 如果return 非 promise类型,则状态会一直是从 pending-fulfilled的成功状态
// 如果return promise类型,根据新的promise对象的结果决定是 pending-fulfilled 还是 pending-rejected
}).then((res) => {
console.log("奖金2",res);
}).catch((err) => {
console.log("没有",err);
})
封装形成链式
function ajax(url){
return new Promise((resolve,reject) => {
let xhr = new XMLHttpRequest();
xhr.open("get",url,true);
xhr.send();
xhr.onreadystatechange = function(){
if(xhr.status >= 200 && xhr.status < 300){
resolve(JSON.parse(xhr.responseText));
}else{
reject(xhr.responseText);
}
}
})
}
ajax("./1.json").then(res => {
console.log(res);
// 注意:这里的ajax的res参数只是为了演示,并没有接收该参数
return ajax("./2.json",res);
}).then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
Promise.all()
let pro1 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve(1000);
},1000)
})
let pro2 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve(2000);
},2000)
})
let pro3 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve(3000);
},3000)
})
// showloading
// 执行完all内的参数所有 Promise,则走then得到回调函数返回值
Promise.all([pro1,pro2,pro3]).then(res => {
// hideloading
// res 返回一个数组,为调用resolve的参数值
console.log(res);
}).catch(err => {
console.log(err);
})
Promise.race()
let pro1 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve(1000);
},1000)
})
let pro2 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve(2000);
},2000)
})
let pro3 = new Promise(function(resolve,reject){
setTimeout(() => {
resolve(3000);
},3000)
})
// 参数内的Promise 有一个成功则会走then后回调函数
Promise.race([pro1,pro2,pro3]).then(res => {
// res 返回一个数组,为调用resolve的参数值
console.log(res);
}).catch(err => {
console.log(err);
})
只要 pro1、pro2、pro3之中有一个实例率先改变状态,p的状态就跟着改变,率先改变的 Promise 实例的返回值传递给 Promise.ract()的回调函数