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标签之间

    <script>
        // js 代码    
    </script>
  2. 引入js脚本

    <script src="js脚本路径"></script>
    • 注意,到了框架之后,引入方式会有不同

二、变量与数据类型

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种的字符串如何表示?

<a href="1.html">超链接</a>

java

String s1 = "<a href=\"1.html\">超链接</a>";
​
String s2 = """<a href="1.html">超链接</a> """;

js

let s1 = '<a href="1.html">超链接</a>';
​
let s2 = `<a href="1.html">超链接</a>`;

  • 模板字符串(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)

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

页面有元素

<p id = "p1">点我啊</p>

此元素有一个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) 显示 <protorype>

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(结果 => {...})
// 后续代码
  • 后续代码不必等待结果返回就可以执行

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钟月一人

码字整理不易,感谢各位大佬支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值