• JavaScript基础知识总结


    目录

    一、js代码位置

    二、变量与数据类型

    1、声明变量

    2、基本类型(7种基本类型)

    1、undefined和null

    2、String ⭐

    模板字符串(Template strings)

    3、number和bigint ⭐

    4、boolean ⭐

    5、symbol

    3、对象类型

    1、Function ⭐⭐

    1、默认参数

    2、匿名函数

    3、箭头函数

    4、函数是对象

    5、函数作用域

    6、闭包

    7、let、var与作用域

    2、Array ⭐

    1、push、shift、unshift、splice

    2、join

    3、map、filter、forEach

    高阶函数:map,filter,forEach

    回调函数: 例如作为参数传入的函数

    4、split

    5、升序,降序,洗牌

    6、.find()

    7、去重

    8、数组和 (解构)

    9、差集、交集、并集

    3、Object ⭐⭐

    属性

    方法

    get、set

    1、语法

    2、特殊:属性增删

    3、用动object.defineProperty()对象态添加 get,set

    4、特殊:this (this的三种情况,一种特例)

    5、特殊:原型继承(对象之间)

    6、特色:基于函数的原型继承

    函数职责

    4、JSON

    1、 json对象 与 js对象 的区别在哪儿呢???

    2、json 字符串与js对象的转换

    3、JSON语法

    5、动态类型

    三、运算符与表达式 ⭐

    1、 ===(严格相等)

    2、||(逻辑或)

    3、?? 与 ?.

    4、...

    5、[]{}

    四、控制语句

    1、for in

    2、for of

    3、try catch

    五、Fetch API


    一、js代码位置

    1. 放在script标签之间

    2. 引入js脚本

      • 注意,到了框架之后,引入方式会有不同

    二、变量与数据类型

    1、声明变量
    • let

      let 变量名 = 值;
      • let 声明的变量可以被多次赋值

        let a = 100; // 初始值是100
        a = 200; // ok,被重新赋值为200
    • const

      const 常量 = 值;
      • const 修饰的叫常量,只能赋值一次

        const b = 300; //初始值是300
        b = 400; //error,不能再赋值 
      • const 并不意味着它引用的内容不可修改,例如

        const c = [1,2,3];
        c[2] = 4;          //ok,数组内容被修改成[1,2,4]
        c = [5,6];         // error.不能再次赋值
    • var

      var声明的变量可以被多次赋值,例如

      let a = 100; // 初始值是100
      a = 200; // ok,被重新赋值为200
    2、基本类型(7种基本类型)
    1、undefined和null
    • 执行表达式或函数,没有返回结果,出现undefined

    • 访问数组不存在的元素,访问对象不存在的属性,出现undefined

    • 定义变量,没有初始化,出现undefined

      二者共同点

      • 都没有属性、方法

      • Nullish(undefined和null共同的称呼)

      二者区别

      • undefined 由 js 产生

      • null 有程序员提供

    2、String ⭐

    html 代码如下,用java和js种的字符串如何表示?

    超链接

    java

    String s1 = "超链接";
    ​
    String s2 = """超链接 """;

    js

    let s1 = '超链接';
    ​
    let s2 = `超链接`;

    • 模板字符串(Template strings)

      需求:拼接URI的请求参数,如

      /test?name=zhang&age=18
      /test?name=li&age=20

      传统方法拼接:可读性低

      let name = ; //zhang  li  ...
      let age = ; // 18 20 ...
      ​
      let uri = "/test?name" + name + "&age=" + age;

      模板字符串方式:可读性高

      let name = ; //zhang  li  ...
      let age = ; // 18 20 ...
      ​
      // 模板字符串方式 需要使用反引号使用
      let uri = `/test?name=${name}&age=${age}`
    3、number和bigint ⭐
    • number 类型表示的是双精度浮动小数,例如

       10 / 3;   //结果 3.3333333333333335

      既然是浮点小数,那么可以除零

      10 / 0;      // 结果 Infinity 正无穷大
      -10 / 0;     // 结果 -Infinity 负无穷大

      浮点小数都有运算精度问题,例如

      2.0 - 1.1    // 结果 0.899999999999999
    • 字符串转数字

      parseInt("10");          // 结果是数字 10
      parseInt("10.5");        // 结果是数字 10,去除了小数部分
      parseInt("10") / 3;      // 结果仍是为 number 浮点数,因此结果为 3.3333333333333335
      ​
      parseInt("abc");         // 转换失败,结果是特殊值 NaN (Not a Number)
    • 需要表示真正的整数,需要用 bigint,数字的结尾用 n 表示它是一个 bigint 类型

      10n / 3n;                // 结果 3n,按整数除法处理
    4、boolean ⭐
    • Truthy

    • Falsy

    在js种,并不是 boolean 才能用于条件判断,你可以在if语句种使用【数字】、【字符串】...自拍为判断条件

    let b = 1;
    ​
    if(b){                      // true
        console.log("进入了");
    }

    这时就有一个规则,当需要条件判断时,这个值被当作 true 还是 false,当作 true 的值归类为 truthy,当作 false的值归类为 falsy

    • falsy

      • false

      • Nullish(null,undefined)

      • 0 或 0n 或 NaN(0和 非数字)

      • "" 或 '' 或 `` (长度为零的空字符串)

    5、symbol
    3、对象类型
    1、Function ⭐⭐

    定义

    function 函数名(参数){
         // 函数体
         return 结果;  // 不是必须的
    }

    例子

    function add(a,b){
        return a + b;
    }

    调用函数

    函数名(实参);

    例子

    add(1,2);       // 返回 3
    add('a','b');   // 返回 ad
    add(4,5,6);     // 返回 9,第三个参数没有被用到,不会报错
    add(1);         // 返回 NaN,这是 b 没有定义是 undefined,undefined做数学运算结果就是 NaN
    1、默认参数

    java中(spring)要实现默认参数的效果

    @RestController
    public class MyController {
        @RequestMapping("/page")
        @ResponseBody
        public void page(
            @RequestParam(defaultValue="1") int page,
            @RequestParam(defaultValue="10") int siza
        ){
            // ...
        }
    }

    js

    function pagination(page = 1,size = 10){
        console.log(page,size)
    }
    ​
    // 显示默认值
    pagination()             // 1  10
    ​
    // page 显示默认值
    pagination(undefined,20) // 1  20
    ​
    // size 显示默认值
    pagination(2)            // 2  10 

    2、匿名函数

    语法

    (function(参数){
         // 函数体
         return 结果;
    })

    (function(a,b){
         return a + b;
    })

    第一种场景:定义完毕后立刻调用

    (function(a,b){
         return a + b;
    })(1,2)

    第二种场景:作为其它对象的方法,例如

    页面有元素

    点我啊

    此元素有一个onclick方法,会在鼠标单击这个元素后被执行,onclick方法刚开始是null,需要赋值后才能使用

    document.getElementById("p1").onclick = (function(){
        console.log("鼠标单机了...")
    });

    3、箭头函数
    (参数) => {
         // 函数体
         return 结果;
    }
    • 如果没有参数,()还是要保留

    • 如果只有一个参数,()可以省略

    • 如果函数体内只有一行代码,{}可以省略

    • 如果函数体内的一行代码是返回代码,那么return也可以省略

    例:

    document.getElementById("p1").onclick = () =>  console.log("鼠标单机了...箭头函数")
    
    function abc(){
        console.log("bb");
    }
    ​
    document.getElementById("p1").onclick = abc;

    4、函数是对象

    以下形式在 js 中非常常见!

    1. 可以参与赋值,例,具名函数也能参与赋值

      function abc(){
          console.log("bb");
      }
      ​
      document.getElementById("p1").onclick = abc;
      ​
      // 如果console.log(abc) 看不到对象的内部结构
      // 就是用console.dir()  查看对象的内部结构
      console.dir(abc)

    2. 有属性、有方法

      f abc()
         arguments: null
         caller: null
         length: 0
         name: "abc"
         ➡prototype: {constructor: f}
         [[FunctionLocation]]: VM1962:1
         ➡[[Prototype]]: f()
         ➡[[Scopes]]: Scopes[1]
      • 其中带有 f 标记的是方法,不带的是属性

      • 带有➡符号的可以继续展开,限于篇幅省略了

      • 带有 [[ ]] 的是内置属性,不能访问,只能查看

      • 相对重要的是 [[Prototype]] 和 [[Scopes]] 会在后面继承和作用域时讲到

    3. 可以作为方法参数

      function a(){
          console.log('a');
      }
      ​
      // 接受了函数作为参数的函数叫做 "高阶函数"
      function b(fn){         //fn 将来可以是一个函数对象
          console.log('b');
          fn();               // 调用函数对象
      }
      ​
      // 将来调用b的时候可以把a传进去
      b(a)

    4. 可以作为方法返回值

      // c函数把b函数当成了自己的返回值,那么c函数就是高阶函数
      function c(){
          console.log("c");
          function d(){
              console.log("d");
          }
          return d;
      }
      ​
      c();  // 返回结果 c    f d(){ console.log("d"); }
      c()();  // 返回函数对象   c  d

    5、函数作用域

    函数可以嵌套( js 代码中很常见,只是嵌套的形式更多是匿名函数,箭头函数)

    function a(){
        function b(){
        
        }
    }

    看下面的例子

    function c(){
        var z = 30;
    }
    var x = 10;
    function a(){
        var y = 20;
        function b(){
            // 看这里
            console.log(x,y);
        }
        b();
    }
    a();
    • 以函数为分界线划定作用域,所有函数之外是全局作用域

    • 查找变量时,由内向外查找

      • 在内层作用域找到变量,就会停止查找,不会再找外层

      • 所用作用域都找不到变量,报错

    • 作用域本质上时函数对象的属性,可以通过 console.dir 来查看调式

    6、闭包
    var x = 10;
    function a(){
        var y = 20;
        function b(){
          console.log(x,y);
        }
        return b;
    }
    a()();   // 在外面执行了 b
    • 函数定义时,他的作用域已经确定好了,因此无论函数将来去了哪,都能从它的作用域中找到当时哪些变量

    • 别被概念忽悠了,闭包就是指函数能够访问自己的作用域中变量

    7、let、var与作用域
    • 如果函数外层引用的是let变量,那么外层普通的{}也会作为作用域边界,最外层的let 也占一个 script 作用域

      let x = 10;
      if(true){
          let y = 20;
          function b(){
              console.log(x,y);
          }
          console.dir(b);
      }
      ​
      // 3个作用域(不包含自己):1、if() 2、let x = 10 3、Global
    • 如果函数外层引用的是 var 变量,外层普通的 {} 不会被视为边界

      var x = 10;
      if(true){
          var y = 20;
          function b(){
              console.log(x,y)
          }
          console.dir(b);
      }
      ​
      // 1个作用域(不包含自己) 1、Global
    • 如果 var 变量出现了重名,则他俩会被视为同一作用域中的同一个变量

      var e = 10;
      if(true){
          var e = 20;
          console.log(e); // 打印 20
      }
      console.log(e);     // 因为是同一个变量,还是打印 20
    • 如果是let,则视为两个作用域中的两个变量

      let e = 10;
      if(true){
          let e = 20;
          console.log(e);  // 打印 20
      }
      console.log(e);     // 打印10
    • 要想里面的 e 和外面的 e 能区分开来,最简单的办法时改成let,或者用函数来界定作用域范围

      var e = 10;
      if(true){
          function b(){
              var e = 20;
              console.log(e); 
          } 
      }
      console.log(e); 

    2、Array ⭐

    语法

    // 创建数组
    let arr = [1,2,3];
    ​
    // 获取数组元素
    console.log(arr[0]); // 输出 1
    ​
    // 修改数组元素
    arr[0] = 5;    // 数组元素变成了 [5,2,3]
    ​
    // 遍历数组元素,其中 length 是数组属性, 代表数组长度
    for(let i = 0; i < arr.length; i++){
        console.log(arr[i])
    }

    API

    1、push、shift、unshift、splice
    let arr = [1,2,3]
    ​
    arr.push(4);       // 向数组尾部(右侧)添加元素,结果 [1,2,3,4]
    arr.shift();       // 从数组头部(左侧)移除元素,结果 [2,3,4]
    arr.splice(1,1)    // 删除【参数1】索引位置的【参数2】个元素,结果[2,4]
    arr.splice(1,0,1)  // 在【参数1】索引位置的添加【参数3】元素并且【参数3】的索引为【参数1】
                       //  结果[2,1,4] 【参数2】的意思是删除的意思0是删除0个元素
    arr.unshift(100)   // 向数组头部(左侧)添加元素,结果[100,2,4]
    arr.slice(start,end)// slice()通过索引位置获取新的数组,该方法不会修改原数组,只是返回一个新的子数组。  左闭右开 [start,end)
                       // 【参数1】:start - 必填,设定新数组的起始位置;如果是负数,则表示从数组尾部开始算起(-1指最后一个元素,-2 指倒数第二个元素,以此类推)。
                      // 【参数2】end - 可选;设定新数组的结束位置;如果不填写该参数,默认到数组结尾;如果是负数,则表示从数组尾部开始算起(-1 指最后一个元素,-2指倒数第                        二个元素,以此类推)。
    Array.splice(start,delete_count,value,...) // 插入、删除、替换数组
    // (1) start:开始插入和(或)删除的数组元素的下标。
    // (2) delete_count:结束截取的数组下标,如果end是负数,表明从数组尾部开始计算.
    // (3)要插入数组的元素。value,-..:
    // 返回:如果从数组中删除了元素,则返回的是被删除的元素的数组
    2、join
    let arr = ['a','b','c'];
    ​
    arr.join();       // 默认使用【,】作为连接符,结果'a,b,c'
    arr.join('');     // 结果 'abc'
    arr.join('-');    // 结果 'a-b-c'
    3、map、filter、forEach

    map 例子

    let arr = [1,2,3,6];
    ​
    // [10,20,30,60]
    function a(i){      // 代表的新旧元素之间的变化规则
        return i * 10;
    }
    ​
    arr.map(a);   // 具名函数,结果 [10,20,30,60]
    // ↓ 进一步简化
    arr.map( (i)=>{return i * 10}); // 箭头函数
    // ↓ 进一步简化
    arr.map( i => i * 10); // 箭头函数
    • 传给 map 的函数,参数代表旧元素,返回值代表新元素,map的内部实现(伪代码)

      function map(a){    // 参数是一个函数
          let narr = [];
          for(let i = 0; i < arr.length; i++){
            let o = arr[i];  // 旧元素
            let n = a(o);    // 新元素
            narr.push(n);
         }
          return narr;
      }

    filter 例子

    let arr = [1,2,3,6];
    ​
    arr.filter( i => i % 2 == 1); // 结果 [1,3]
    • 传给 filter 的函数,参数代表旧元素,返回值 true 表示要留下的元素

    forEach例子

    let arr = [1,2,3,6];
    ​
    for(let i = 0; i < arr.length; i++){
        console.log(arr[i])
    }
    ​
    arr.forEach( i => console.log(i));
    arr.forEach((v,i) => {console.log(`n[${i}]=${v}`)})
    • 高阶函数:map,filter,forEach
    • 回调函数: 例如作为参数传入的函数
    4、split

    字符串转数组

    let arr4 = '中国人'.split('')
    console.log(arr4)    // 输出结果 ['中','国','人']
    5、升序,降序,洗牌

    注意:num是一个非空数字数组

    • 升序:num.sort((a,b) => a-b)

    • 降序:num.sort((a,b) => b-a)

    • 洗牌:num.sort(() => Math.random() > .5 ? a : b)

    6、.find()

    根据元素查找元素

    let n = [1,2,3,4,5,6,7,8,9,10,2,4,2,1]
    console.log(n.find(e => e === 10)) // 10
    7、去重
    // 去重
    console.log('-------------去重')
    let nn = [1,2,3,4,5,6,5,7,5,8,6,9,4,6]
    console.log(nn)
    // 方法1 过滤
    let arr = nn.filter((v,i)=>nn.indexOf(v)===i)
    console.log(arr)
    // 方法2  set方法
    let arr2 = [...new Set(nn)]
    console.log(arr2)
    8、数组和 (解构)
    let nn = [1,2,3,4,5,6,5,7,5,8,6,9,4,6]
    let n2 = [1,2,3,4]
    console.log(nn)
    console.log(n2)
    console.log('-------------数组和')
    nn.push(...n2)
    console.log(nn)
    9、差集、交集、并集
    let a1 = [1, 2, 3]
    let a2 = [11, 22, 33, 1, 2, 3]
    ​
    // 差集
    let a4 = a2.filter(e => !a1.includes(e))
    console.log(a4)
    ​
    // 交集
    let a3 = a1.filter(e => a2.includes(e))
    console.log(a3)
    ​
    // 并和 去重
    a1.push(...a2.filter(e => !a1.includes(e)))
    console.log(a1)

    3、Object ⭐⭐
    • 属性
    • 方法
    • get、set
    1、语法
    let obj = {
        属性名: 值,
        方法名: 函数,
        get 属性名() {},
        set 属性名(新值) {}
    }

    例1 写法1

    let stu1 = {
        name: "小明",
        age: 18,
        study: function(){
            console.log(this.name + "爱学习");
        }
    }

    例2 写法2

    let name = "小黑";
    let age = 20;
    let study = function(){
        console.log(this.name + "爱学习");
    }
    ​
    let stu2 = {
        name,
        age,
        study
    }

    例3 (例1的简写方式 重点)⭐

    let stu3 = {
        name: "小明",
        age: 18,
        study(){
            console.log(this.name + "爱学习");
        }
    }
    • 注意:对象方法这么写,仅限于对象内部

    例4

    let stu4 = {
        _name: null,      // 类似于java中私有成员变量
        get name(){
            console.log("进入了get");
            return this._name;
        },
        set name(name){
            console.log("进入了set");
            this._name = name;
        } 
    }

    调用 get,set

    stu4.name = "小白";        // 调用set 赋值语句
    ​
    console.log(stu4.name)    //  调用get
    2、特殊:属性增删

    对比以下 Java 中的 Object

    • Java 的 Object 是以类作为模板来创建,对象不能脱离类模板的范围,一个对象的属性,能用的方法都是确定好的

    • js 的对象,不需要什么模板,它的属性和方法可以随时加减

      let stu = {name: '张三'};
      ​
      stu.age = 18;  // 这个age属性是创建stu后加上的
      delete stu.age;  // 删除 stu这个对象中的age属性
      ​
      stu.study = function() {
          console.log(this.name + "在学习");  // 这个study方法是后加的 
      }
    3、用动object.defineProperty()对象态添加 get,set
    let stu = {
        _name:null
    };
    ​
    // 第一个参数 给哪一个对象定义属性
    // 第二个参数 属性名 不要和_name冲突
    // 第三个参数 包含了get,set的定义
    object.defineProperty(stu,"name",{
        get(){
            return this._name
        },
        set(name){
            this._name = name;
        }
    });
    4、特殊:this (this的三种情况,一种特例)

    先来对 Java 中的 this 有个理解

    public class TestMethod{
        
        static class Student{
            private String name;
            
            public Student(String name){
                this.name = name;
            }
            
            // 隐式参数Student this
            public void study(Student this,String subject){
                System.out.println(this.name + ": 在学习" + subject);
            }
            
        }
            public static void main(String[] args){
                Student stu = new Student("小明");
                
                // 下面的代码,本质上是执行 study(stu, "java"),因此 this 就是                stu
                stu.study("java");
            }
        
    }

    js 中的 this 也是隐式参数,但是它与函数运行时上下文相关

    ①、一个”落单“的函数

    function study(subject){
        console.log(this.name + "在学习" + subject);
    }

    测试以下

    study("js");       // 输出 在学习  js

    这是因为此时函数执行,全局对象 window 被当作了 this, window 对象的 name 属性是空串

    ②、同样的函数,如果作为对象的方法

    let stu = {
        name: "小白",
        study
    }

    这种情况下,会将当前对象作为 this

    ③、.call 还可以动态改变this

    let stu = {name:"小黑"};
    // 第一个参数:你要把this视为谁?
    // 第二个参数:传入study方法需要的形参
    study.call(stu,"js");     // 输出  小黑在学习  js

    这回 study 执行时,就把 call 的第一个参数 stu 作为 this

    例外:在箭头函数内出现的 this,以外层 this 理解

    用匿名函数

    let stu = {
        name: "小花",
        friends: ["小白","小黑","小明"],
        play:function(){   // play:function() == play()
            this.friends.forEach(function(e){
                console.log(this.name + "与" + e + "在玩耍");
            });
        }
    }
    stu.play();
    // 第一个this指的时stu  第二个this指的是window(因为第二个函数时落单的函数)
    • this.name 所在的函数时【落单】的函数,因此 this 代表 window

      输出结果为

      与小白在玩耍
      与小黑在玩耍
      与小明在玩耍

    用箭头函数

    let stu = {
        name: "小花",
        friends: ["小白","小黑","小明"],
        play(){
            this.friends.forEach(e =>{
                console.log(this.name + "与" + e + "在玩耍");
            });
        }
    }
    //在箭头函数内出现的 this,以外层 this 理解
    • this.name 所在的函数是箭头函数,因此 this 要看它外层的 play 函数, play 又是属于 stu 的方法,因此 this 代表 stu 对象

      输出结果为

      小花与小白在玩耍
      小花与小黑在玩耍
      小花与小明在玩耍

    不用箭头函数的做法

    let stu = {
        name: "小花",
        friends: ["小白","小黑","小明"],
        play(){
           let me =  this;
            this.friends.forEach(function(e){
                console.log(me.name + "与" + e + "在玩耍");
            });
        }
    }
    5、特殊:原型继承(对象之间)
    let father = {
        f1: '父属性',
        m1: function(){
            console.log("父方法");
        }
    }
    ​
    // .create:以父对象为原型创建一个子对象
    let son = Object.create(father);
    ​
    console.log(son.f1);   // 打印 父属性
    son.m1                 // 打印 父方法
    • father 是父对象,son 去调用 .m1 或 .f1 时,自身对象没有,就到父对象找

    • son 自己可以添加自己的属性和方法

    • son 里有特殊属性 __proto__ 代表它的父对象,js 术语:son 的原型对象

    • 不同浏览器对打印 son 的 __proto__ 属性时显示不同

      • Edge 打印 console.dir(son) 显示 [[prototype]]

      • Firefox 打印 console.dir(son) 显示

    6、特色:基于函数的原型继承

    出于方便的原因,js 又提供了一种基于函数的原型继承

    函数职责
    1. 负责创建子对象,给子对象提供属性,方法,功能上相当于构造方法

    2. 函数有个特殊的属性 prototype,它就是函数创建的子对象的父对象

    注意! 名字有差异,这个属性的作用就是为新对象提供原型

    function cons(f2){
        // 创建子对象(this),给子对象提供属性和方法
        this.f2 = f2,
        this.m2 = function (){
            console.log("子方法");
        }
    }
    // cons.prototype 就是父对象
    cons.prototype.f1 = "父属性";
    cons.prtotype.m1 = function(){
        console.log("父方法");
    }

    配合 new 关键字,创建子对象

    let son = new cons("子属性");

    子对象的__proto__就是函数的 prototype 属性

    4、JSON

    之前我们将 http 请求格式时,讲过 json 这种数据格式,他的语法看起来与 js 对象非常相似,例如:

    一个 json 对象可以张这样:

    {
        "name":"张三",
        "age":18
    }

    一个 js 对象长这样

    {
        name:"张三",
        age:18
    }
    1、 json对象 与 js对象 的区别在哪儿呢???
    1. 本质不同

    • json 对象本质上就是个字符串,它的职责是作为客户端和服务器之间传递数据的一种格式,它的属性只是样子货

    • js 对象是切切实实的对象,可以有属性方法

    1. 语法细节不同

    • json 中只能有null、true|false、数字、字符串(只有双引号)、对象、数组

    • json 中不能有除以上的其他 js 对象的特性、如方法等

    • json 中的属性必须用双引号引起来

    2、json 字符串与js对象的转换
    // 把 json 字符串转化为 js 对象   返回对象js对象
    JSON.parse(json字符串);
    // 把 js 对象转换成 json 字符串   返回json字符串
    JSON.stringify(js对象);
    3、JSON语法
    let json = `{
        "name":"张三",
        "age":18
    }`;
    ​
    let obj = JSON.parse(json);
    5、动态类型

    静态类型语言,如 Java,值有类型,变量也有类型、赋值给变量时,类型要相符

    int a = 10;
    String b = "abc";
    ​
    int c = "abc";  // 错误

    而 js 属于动态类型语言,值有类型,但变量没有类型,赋值给变量时,没要求

    例如

    let a = 200;
    ​
    let b = 100;
    b = 'abc';
    b = true;

    动态类型看起来比较灵活,但变量没有类型,会给后期维护带来困难,例如

    function test(obj){
         // obj 的类型未知,必须根据不同类型做出各种容错处理
    }

    三、运算符与表达式 ⭐

    • + - * / % **

    • += -= *= /= %= **=

    • ++ --

    • 位移算、移位运算(估计大家用不着,用到时候上网搜索)

    • == != > >= < <=

    • === !==

    • && || !

    • ?? ?.

    • ...

    • 解构赋值 []{}⭐

    **:乘方

    **=:乘方等

    1、 ===(严格相等)

    严格相等运算符,用作逻辑判等。

    1 == 1       // 返回 true
    1 == '1'     // 返回 true,会先将右侧的字符串转为数字,再做比较
    1 === '1'    // 返回 false。类型不等,直接返回 false

    补充:typeod 查看某个值的类型

    typeof 1;    // 返回 'number'
    typeof 'a';  // 返回 'string'
    2、||(逻辑或)

    需求,如果参数 n 没有传递,给它一个 【男】

    推荐做法

    function test(n = '男'){
        console.log(n);
    }

    你可能的做法

    function test(n){
        if(n === undefined){
            n = '男';
        }
        console.log(n)
    }

    还可能时这样

    function test(n){
        n = (n === undefined) ? '男' : n;
        console.log(n);
    }

    一些老旧代码中可能的做法(不推荐,有潜在问题

    function test(n){
        n = n || '男';
        console.log(n);
    }

    它的语法时

    值1 || 值2

    如果值1 时 Truthy,返回值1,如果值1 时 Falsy 返回值2

    3、?? 与 ?.

    ?. 可选链操作符用于访问可能为空或未定义的属性或方法,它允许我们安全地访问嵌套对象的属性

    ?? 空值合并操作符用于检查一个变量是否为 null 或 undefined,如果是,则返回一个默认值,否则返回该变量的值。与传统的逻辑运算符 || 不同,?? 只会在左侧的值为 null 或 undefined 时返回右侧的默认值,对于其他假值(如空字符串、0、false 等)并不会返回默认值,而是会返回它本身。

    需求,如果参数 n 没有传递值或是 null,给它一个【男】

    如果用传统办法

    function test(n){
        if(n === undefined || n === null){
            n = '男';
        }
        console.log(n);
    }

    用 ??

    function test(n){
        n = n ?? '男';
        console.log(n)
    }

    需求,函数参数是一个对象,可能包含有子属性

    例如,参数可能是

    let stu1 = {
        name:"张三",
        address:{
            city:'北京'
        }
    }
    ​
    let stu2 = {
        name:"李四",
    }
    ​
    let stu3 = {
        name:"李四",
        address: null
    }

    现在要访问子属性

    function test(stu){
        console.log(stu.address.city)
    }

    现在希望当某个属性是 nullish 时,短路并返回 undefined

    function test(stu){
        console.log(stu.address?.city)
    }

    用传统办法

    function test(stu){
        if(stu.address === undefined || stu.address === null){
            console.log(undefined);
            return;
        }
        console.log(stu.address.city);
    }
    4、...

    展开运运算符

    作用1:打散数组传递给多个参数

    let arr = [1,2,3];
    ​
    function test(a,b,c){
        console.log(a,b,c);
    }
    • 传统的打散写法

      test(arr[0],arr[1],arr[2]);   // 输出 1,2,3
    • 展开运算符写法

      test(...arr);       // 输出 1,2,3
      • 打散可以理解为【去掉了】数组外侧的中括号,只剩下数组元素

    作用2:复制数组或对象

    数组

    let arr1 = [1,2,3];
    ​
    let arr2 = [...arr1]; // 复制数组

    对象

    let obj1 = {name:'张三',age:18};
    ​
    let obj2 = {...obj1};  // 复制对象

    注意:展开运算符复制属于浅拷贝(只能复制一层,多层的话就是引用了),例如

    let o1 = {name:'张三',address:{city:'北京'}}
    ​
    let o2 = {...o1};

    作用3:合并数组或对象

    合并数组

    let a1 = [1,2];
    let a2 = [3,4];
    ​
    let b1 = [...a1,...a2];   // 合并数组  [1,2,3,4]
    let b2 = [...a2,5,...a1]  // 输出 [3,4,5,1,2]

    合并对象

    let o1 = {name:'张三'};
    let o2 = {age:18};
    let o3 = {name:'李四'};
    ​
    let n1 = {...o1, ...o2};   // 结果 {name:'张三',age:18}
    let n2 = {...o1, ...o2, ...o3};  // 结果 {name:'李四',age:18} 
    5、[]{}

    解构赋值

    []

    用在声明变量是

    let arr = [1,2,3];
    ​
    // 我们把中括号叫做数组的解构赋值
    let [a,b,c] = arr      // 结果 a=1,b=2,c=3

    用在声明参数时

    let arr = [1,2,3];
    ​
    function test([a,b,c]){
        console.log(a,b,c);
    }
    ​
    test(arr);       // 结果 a=1,b=2,c=3

    {}

    用在声明变量时

    let obj = {name:"张三",age:18};
    ​
    // 声明的变量名称要和obj的对象属性一致
    let {name,age} = obj;

    用在声明参数时

    let obj = {name:"张三",age:18};
    ​
    function test({name,age}){
        console.log(name,age);
    }
    ​
    test (obj);

    四、控制语句

    • if ... else

    • switch

    • while

    • do ... while

    • for

    • for ... in

    • for ... of

    • try ... catch

    1、for in

    主要用来遍历对象

    let father = {name:'张三',age:18,study:function(){}};
    ​
    for(const n in father){
        console.log(n);
    }
    // 结果   name  age   study
    • 其中 const n 代表遍历出来的属性名

    • 注意1:方法名也能被遍历出来(它其实也算一种特殊属性)

    • 注意2:遍历子对象时,父对象的属性会跟着遍历出来

      let son = object.create(father);
      son.sex = "男";
      ​
      for(const n in son){
          console.log(n);
      }
      ​
      // 结果 sex name age study
    • 注意3:在 for in 内获取属性值,要使用 [] 语法,而不能用 . 语法

      for(const n in son){
          console.log(n,son[n]);
      }
      ​
      // 结果
      // sex    男
      // name   张三
      // age    18
      // study  f (){}
    2、for of

    主要用来遍历数组,也可以时其它可迭代对象,如Map,Set等

    let a1 = [1,2,3];
    ​
    for(const i of a1){
        console.log(i);
    }
    ​
    ​
    let a2 = [
        {name:'张三',age:18},
        {name:'李四',age:20},
        {name:'王五',age:22}
    ];
    ​
    for(const obj of a2){
        console.log(obj.name,obj.age);
    }
    ​
    for(const {name,age} of a2){
        console.log(name,age);
    }
    3、try catch
    let stu1 = {name:'张三',age:18,address:{city:'北京'}};
    let stu2 = {name:'张三',age:18};
    ​
    function test(stu){
        try{
            console.log(stu.address.city);    
        } catch(e){
            console.log('出现了异常',e.message);
        }
        
    }

    五、Fetch API

    Fetch API 可以用来获取远程数据,他有两种方式接受结果,同步方式与异步方式

    格式

    fetch(url,options)  // 返回 Promise对象

    同步方式

    // const 结果 = await fetch(url,options);
    const 结果 = await Promise;
    // 后续代码
    • await 关键字必须在一个标记了 async 的 function 内来使用

    • 后续代码不会在结果返回前执行

    异步方式

    fetch(url,options).then(结果 => {...})
    // 后续代码
    • 后续代码不必等待结果返回就可以执行

  • 相关阅读:
    随机硬件地址?私有 WiFi 地址?随机 MAC 地址?
    3A4000架构银河麒麟V10编译安装filezilla
    【CSDN 每日一练 ★☆☆】【蛮力/双指针】删除排序链表中的重复元素
    数据库设计 ER图
    【无标题】
    失败驱动开发
    css设置z-index为无穷大
    adb详细教程(四)-使用adb启动应用、关闭应用、清空应用数据、获取设备已安装应用列表
    [黑马程序员Pandas教程]——DataFrame数据的增删改操作
    使用StreamLoad实现数据同步到StarRocks
  • 原文地址:https://blog.csdn.net/WANGLI123956/article/details/132817555