1.let变量

  • let没有变量提升
let myName = "haonan";
function test(){
    console.log(myName);
    let myName = "nan";
}
test(); // 报错

打印下面重新定义了 myName,则存在暂存性死区,打印则会报错,如果打印下方没有重新定义,则不会报错值为初始定义的 myName

2.Number——API

  • 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
    

3.Math——API

  • 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
    

4.Array——API

  • 数组.find(function(item){ }) | 数组.findIndex(...)

    • 该方法主要应用于查找第一个符合条件的数组元素
    • 它的参数是一个回调函数,在回调函数中可以写你要查找元素的条件,当条件成立为 true 时,返回该元素。如果没有符合条件的元素,返回值为 undefined
    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));
    

5.对象扩展

  • 对象简写

    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
    

6.Symbol

表示独一无二的值,它属于 JavaScript 语言的原生数据类型之一

  • 基本使用

    let s1 = Symbol(); // 生成了一个symbol类型数据
    let s2 = Symbol();
    
    console.log(s1 === s2); // false
    
    • 不能进行运算
    • 可以显示调用toString()
    console.log(s1.toString()+"aaa");
    
    • 隐式转换boolean —— true
    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)

7.Iterator迭代器

  • 作用

    • 为各种数据结构提供一个统一、简便的访问接口
    • 使数据结构的成员能够按某种次序排列
    • ES6 创造了一种新的遍历命令 for...of循环,Iterator 接口主要提供for...of循环
    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 接口的数据结构:

    • Array
    • Set
    • Map
    • String
    • arguments 对象
    • NodeList 对象
  • 对于对象进行 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);
  }

8.Set结构

类似数组,但成员都是唯一的,没有重复的值

  • 使用

    let s1 = new Set([1,2,3,2,3,2])
    console.log(s1); // 1,2,3
    
  • 实例属性和方法

    • size:返回 Set 实例的成员总数
    • Set.prototype.add(value):添加某个value
    • Set.prototype.delete(value):删除某个value,返回布尔值
    • Set.prototype.has(value):判断是否存在该value,返回布尔值
    • Set.prototype.clear():清楚所有成员,无返回值
  • 遍历

    • Set.prototype.keys():返回键名的遍历器【Set集合键值为同值】
    • Set.prototype.values():返回键值的遍历器
    • Set.prototype.entries():返回键值对的遍历器
    • Set.prototype.forEach():遍历每个成员
  • 复杂数据结构去重

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

9.Map结构

类似对象,建可以是各种类型包括对象

  • 使用

    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);
    
  • 实例的属性和方法

    • size:返回 Map 结构的成员总数
    • Map.prototype.set(key,value):添加key对应的value,返回 Map 结构本身
    • Map.prototype.get(key):根据key获取value值
    • Map.prototype.delete(key):删除某个建
    • Map.prototype.has(key):某个键是否在当前 Map 对象中
    • Map.prototype.clear():清楚所有元素
  • 遍历

    • Map.prototype.keys():返回建
    • Map.prototype.values():返回值
    • Map.prototype.entries():返回键值
    • Map.prototype.forEach():遍历Map所有成员
    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);
    })
    

10.Proxy代理

  • 作用

    • 在对象和对象属性值之间的一个代理,获取该对象的值或者设置该对象的值,以及实例化等等多种操作,都会被拦截,经过这一层可以统一处理,称为代理器
  • 没有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;
        }
    })
    

11.Reflect对象

可以用于获取目标对象的行为,它与 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)
    

12.Promise

是异步编程的一种解决方案,比传统的解决方案回调函数,更合理强大。ES6 将其写进了语言标准,统一了用法,原生提供了 Promise 对象

  • 作用

    • 指定回调函数方式更灵活易懂
    • 解决异步回调地狱的问题
  • 回调地狱

    • 当一个回调函数嵌套一个回调函数的时候,就会出现一个嵌套结构,当嵌套的多了就会出现回调地狱的情况
    • 比如我们发送三个 ajax 请求
      • 第一个正常发送
      • 第二个请求需要第一个请求的结果的某一个值作为参数
      • 第三个请求需要第二个请求的结果重的某一个值作为参数
    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 对象的状态

    • 异步操作未完成 pending
    • 异步操作成果 fulfilled
    • 异步操作失败 rejected

    变化途径只有两种:从 未完成 —— 成功,从 未完成 到——失败

image-20230810204756016.png

  • 封装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);
    })
    
    • 返回值
      • 只有 pro1、pro2、pro3的状态都变成了fulfilled,p的状态才会变成fulfilled,返回值为该三个的返回值形成数组返回给 Promise.all()
      • 只要 pro1、pro2、pro3之中有一个为 rejected,则p的状态就会变成 rejected,此时第一个被 reject 的实例返回值,会传递到Promise.all()的返回值
  • 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()的回调函数

results matching ""

    No results matching ""