JavaScript高级进阶(更新中)-javascript-gao-ji-jin-jie--geng-xin-zhong-(三)

简介: JavaScript高级进阶(更新中)-javascript-gao-ji-jin-jie--geng-xin-zhong-

JavaScript高级进阶(更新中)-javascript-gao-ji-jin-jie--geng-xin-zhong-(二)https://developer.aliyun.com/article/1469504


ES5&ES6对象特性

ES5

对象和函数的原型

JS中每一个对象都有一个特殊的内置属性,这个特殊的对象可以指向其他的对象

  • 我们通过引用对象的属性key来获取一个value时,它会触发 Get 的操作
  • 首先检查该对象是否有对应的属性,如果有的话就使用对象内的
  • 如果对象中没有属性,那么会访问对象的prototype
  • 每一个对象都有一个原型属性

使用方式有两种:

  • 通过对象的 _proto_属性可以获取到(浏览器自己添加的,存在一定的兼容性问题)
  • 通过 Object.getPrototypeOf 方法可以获取

prototype属性是函数特有的属性 我们的对象可以通过Object.getPrototypeOf__proto__来查看原型。

var obj = {
       
    }
    function foo() {
    }
    console.log(foo.prototype);

当我们这个对象有对多个共同值的时候,可以把相同的东西当如原型里,这样每次创建这个对象的时候,就可以直接调用而不是重新创建。

function Student(name, age) {
        this.name = name
        this.age = age
        // 如果我们每个对象都创建那么这两个方法会出现很多的冗余
        // this.running = function () {
        //     console.log(this.name + "running");
        // }
        // this.eating = function () {
        //     console.log(this.name + "eating");
        // }
    }
    Student.prototype.running = function () {
        console.log(this.name + "running");
    }
    Student.prototype.eating = function () {
        console.log(this.name + "eating");
    }
    var stu1 = Student("jjj", 12)
    var stu2 = Student("hhh", 18)

Constructor属性

原型对象上面是有一个属性的:constructor,默认情况下原型都会有一个叫constructor指向当前的对象

function Person() { }
    var PersonProtype = Person.prototype
    console.log(PersonProtype);
    console.log(PersonProtype.constructor);
    console.log(PersonProtype.constructor == Person);

原型对象是可以重写的,当我们需要给原型添加更多的属性的时候一般我们会选择重写原型对象

我们也可以改变原型对象中constructor的指向的使用

//改变指向对象
    Person.prototype={
        constructor:Person
    }
//修改枚举类型
  Object.defineProperty(Person.prototype,"constructor",{
        enumerable:false
    })

这里要注意的是原生的constructor是不可枚举的,但是修改constructor的时候会让constructor的特性被设置为true这个时候需要修改一下对象默认属性设置

创建对象的内存表现

如果我们向对象加入属性在之后的变化:

原型对象默认创建的时候,proto都是指向object的的proto的

多种继承方式

继承

面向对象有三大特性:封装、继承、多态

  • 封装:我们前面将属性和方法封装到一个类中,可以称之为封装的过程
  • 继承:继承是面向对象中非常重要的,不仅仅可以减少重复代码的数量,也是多态前提(纯面向对象中)
  • 多态:不同的对象在执行时表现出不同的形态

这里主要将JS中的继承,在了解继承之前我们需要了解JS中的原型链机制,这个是之后理解的关键

原型链

在js中我们不断的获取原型对象,原型链最顶层的原型对象就是Object的原型对象

[Object: null prototype] {}这种提示一般有两个情况:

  • 该对象有原型,且这个原型的属性指向null或者最顶层了
  • 这个对象有很多的默认属性方法

ps:Object是所有类的父类

我们也可以对原型链做一些自定义操作,比如这样:

var obj = {
    }
    obj.__proto__ = {
    }
    obj.__proto__.__proto__ = {
    }
    obj.__proto__.__proto__.__proto__ = {
        name: "小冷"
    }

原型链实现继承

function Person(){
    this.name = "l"
}
var p = new Person()
stu.prototype = p
//name == l
stu.prototype.studying = function(){
    console.log(this.name+"studying")
}

我们可以通过赋值原型的形式来实现继承,但是有一些弊端

  1. 直接打印对象是看不到属性的
  2. 这个属性会被多个对象共享,如果是引用类型就会造成问题
  3. 不能给父类传递参数,没法定制化

借用构造函数继承

为了解决原型链继承中存在的问题,constructor stealing应运而生 ,借用继承的做法非常简单:在子类型构造函数的内部调用父类型构造函数

  • 因为函数可以任意调用
  • 因此通过apply和call也可以再新创建的对象上实行构造函数
function Person(name, age, height, address) {
        this.name = name
        this.age = age
        this.height = height
        this.address = address
    }
    function Student(name, age, height, address, sno, score) {
        Person.call(this,name, age, height, address)
        this.sno = sno
        this.score = score
    }

可以使用父类的构造函数来实现创造,解决之前原型链的问题 在ES6之前一直是保持的这个方式,但是这个继承方式依然不是很完美

  • 无论在什么情况下,都会调用两次父类构造函数。 一次是创建子类原型,一次是构造函数
  • 所有的子类都会有两份父类的属性

继承最终方案

在继续的发展中, JSON的创立者道格拉斯, 提到了新的继承方法,这也是目前es5 阶段最合适的继承方案 寄生组合继承

  • 结合原型类继承和工厂模式
  • 创建一个封装继承过程的函数,在这个函数的内部来增强对象,最后将这个对象返回
function Person(name, age, height, address) {
        this.name = name
        this.age = age
        this.height = height
        this.address = address
    }
    Person.prototype.running = function () {
        console.log(this.name + " running");
    }
    function Student(name, age, height, address, sno, score) {
        Person.call(this, name, age, height, address)
        this.sno = sno
        this.score = score
    }
    // 原型继承
    var obj = Object.create(Person.prototype)
    console.log(obj.__proto__ === Person.prototype);
    Student.prototype = obj
    // 上到真是环境 会封装用 为了兼容性可以多一个创造类的方法
    function object(o){
    function F(){}
    F.prototype = o
    return new F()
    }
    function inherit(Subtype, Supertype) {
        Subtype.prototype = object(Supertype.prototype)
        // 需要构造方法
        Object.defineProperty(Subtype, "constructor", {
            enumerable: false,
            configurable: this,
            writable: true,
            value: Subtype
        })
    }
    inherit(Student, Person)
    Student.prototype.eating = function () {
        console.log(this.name + "eating");
    }
    var stu = new Student("小明");
    stu.eating()

对象方法补充

hasOwnProperty : 对象是否有某一个属于自己的属性

in/for in 操作符: 判断某个属性是否在对象或者对象的原型上

instanceof : 用于检测构造函数的原型,是否出现在某个实例对象的圆形脸上

isPrototypeOf:用于检测某个对象,是否出现在某个实例对象的原型链上

ES6

class定义关键字

这个关键字主要是用于区别代码的编写方式的,之前编写中创建类和构造函数过于相似,而且代码并不容易理解

  • 在ES6的标准中使用了class关键字来直接定义类
  • 类本质上依然是前面所讲的构造函数、原型链的语法糖
  • 比较少用 一般情况遇不到

使用方法

class Person{}
var Student = class{
    
}

类的构造函数

在创建对象的时候给类传递一些参数

  • 每个类都可以有一个自己的构造函数(方法),这个方法的名称是固定的constructor
  • 当我们通过new操作符,操作一个类的时候会调用这个类的构造函数constructor
  • 构造函数时唯一的 不能出现多个

通过new关键字操作类的时候,会调用这个constructor函数

  1. 在内存中创建一个新的空对象
  2. 对象内部的[[prototype]]属性会被赋值为该类的prototype属性
  3. 构造函数内部的this,会指向创建出来的新对象
  4. 执行构造函数的内部代码
  5. 如果构造函数没有返回非空对象,则返回创建出来的新对象

语法使用

class Person {
      constructor(name, age) {
        this.name = name
        this.age = age
      }
      running() {
        console.log(this.name + "running");
      }
      eating() {
        console.log(this.age + "eating");
      }
    }
    var p1 = new Person("123", 123)
    console.log(p1.name, p1.age)

class 创建的类和function直接创造构造方法创建的类时没有什么区别的

定义访问器

对象的属性描述符时有讲过对象可以添加setter和getter函数的,类同样也是可以的

var ojb = {
    _name:"why",
    set name(value){
        this._name = value
    },
    get name(){
       return this._name
    }
}

类的静态方法

静态方法通常用于定义直接使用类来执行的方法,不需要有类的实例,使用static关键字来定义

class Person{
    constructor(age){
        this.age = age
    }
    static create(){
      return new Person(Math.floor(Math.random()*100))
    }
}

extends 继承

ps : js的继承属于只支持单继承

之前我们在es5 中经过原型链继承,组合继承等等操作才解决继承的一些问题,但是在ES6 中 他给我们提供了一个关键字 : extends

class Person {
     constructor(name, age) {
       this.name = name
       this.age = age
     }
     running() {
       console.log(this.name + "running");
     }
     eating() {
       console.log(this.age + "eating");
     }
   }
   class Teacher extends Person {
     constructor(name, age, title) {
       // this.name = name
       // this.age = age
       super(title)
       this.title = title
     }
     Teaching() {
       console.log(this.name + "Teaching");
     }
   }
   class Student extends Person {
     constructor(name, age, sno) {
       // this.name = name
       // this.age = age
       super(name, age)
       this.sno = sno
     }
     studying() {
       console.log(this.name + "studying");
     }
   }
   var p1 = new Student("123", 123, "123")
   console.log(p1.name, p1.age)
   p1.eating()

我们只需要在类之后用extends 指向需要被继承的类 就可以实现继承

Super 关键字

Class为我们的方法中还提供了super关键字

  • 执行 super.method(...) 来调用一个父类方法
  • 执行 super(...) 来调用一个父类 constructor(只能在我们的 constructor 中)
  • super使用的位置有三个 子类构造函数,实例方法,静态方法

PS: 在子类的构造函数中使用this或者返回默认对象之前,必须先通过super调用父类的构造函数

在JS 中 我们子类也是可以重写父类的方法的,但是当我们既想让子类有自己的操作,还想复用父类的实现,就可以使用super 关键字

class Animal {
      running() {
        console.log("running");
      }
    }
    class dog extends Animal {
      running() {
        console.log("dog four jio");
        super.running()
      }
    }
    var dog = new dog()
    dog.running()

继承内置类

同样 我们可以继承内置类,比如数组 Array 类 加入我们想给数组加一些拓展比如获得第一位 获得最后一位 我们就可以继承数组对象添加我们想要定义的拓展

// 继承内置类
    class CodeArray extends Array {
      get lasItem() {
        return this[this.length - 1]
      }
      get firstItem() {
        return this[0]
      }
    }
    var arr = new CodeArray(12, 14, 15, 16, 20)
    console.log(arr);
    console.log(arr.lasItem());

类的混入mixin

JavaScript的类只支持单继承,混入的思想可以帮助我们利用函数的方式实现嵌套继承,

  • 它可以通过编写混入函数以返回新对象的方式实现多个继承
class Person {
      constructor(name, age) {
        this.name = name
        this.age = age
      }
      swimming() {
        console.log(first)
      }
    }
    function mixinRunner(BaseClass) {
      return class extends BaseClass {
        running() {
          console.log(this.name + " running~")
        }
      }
    }
    function mixinEater(BaseClass) {
      return class extends BaseClass {
        eating() {
          console.log(this.name + " eating~")
        }
      }
    }
    class NewPerson extends mixinEater(mixinRunner(Person)) {
    }
    var NP = new NewPerson();
    NP.swimming()

ES6新的语法糖

ES6中对 对象字面量 进行了增强,称之为 Enhanced object literals

主要包括:

  • 属性的简写:Property Shorthand
  • 方法的简写:Method Shorthand
  • 计算属性名:Computed Property Names

属性的简写

当属性和变量名字完全一样的时候 可以将他省略 之后生成的代码还是和之前无差

/*
    1. 属性的简写
    */
    var name = "123"
    var age = 12
    var obj = {
        name,
        age
    }

方法的简写

/*
    1. 属性的增强
    */
var obj = {
    running:function(){},
    //简写为
    running(){}
}

计算属性名

var address = "us"
 
var obj = {
    [address]: "北京"
}

解构 Destructuring

ES6中新增了一个从数组或对象中方便获取数据的方法,它是一种特殊语法

数组的解构:

  • 基本解构过程
  • 顺序解构
  • 解构出数组:…语法
  • 默认值: undefind
var names  = ["nnn","qqq","lll","fff"]
var [names1,names2,...names] = names
//输出结果 nnn,qqq,[lll,fff]

对象的解构:

  • 基本解构过程
  • 任意顺序
  • 重命名
  • 默认值
var obj = {name:"uuu",age:12,height:1.88}
var {height,name} = obj
//需要重命名
var {height:hei,name} = obj
默认值
var {name,age,grilfrineds:gf = "lucy"} = obj

对象解构的应用:

function getPostion({x,y}){
var a = x+y
}
getPostion({x:10,y:20});

实现函数 apply /call / bind

实现函数内容

首先我们要遵循封装的思想 , apply 和 call 方法 其实就是调用的方式不同而已

所以我们可以将这两个方法调用的共同点封装成一个函数 接下来只需要用不同的方式调用就可以了

function foo(name, 
    ) {
        console.log(this, name, age);
    }
    // foo.apply("aaa", ["hyc", 12])
    // foo.call("aaa", "lebron", 38)
    function execFn(thisArg, otherArgs, fn) {
        // 1、 获取 thisArg 确保是一个对象类型
        thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)
        // thisArg 传入的第一参数是要绑定的this
        Object.defineProperty(thisArg, "fn", {
            enumerable: false,
            configurable: true,
            value: fn
        })
        thisArg.fn(...otherArgs)
        delete thisArg.fn
    }
    Function.prototype.hycApply = function (thisArg, otherArgs) {
        execFn(thisArg, otherArgs, this)
    }
    Function.prototype.hyccall = function (thisArg, ...otherArgs) {
        execFn(thisArg, otherArgs, this)
    }
    foo.hycApply({ name: "hyc" }, ["james", 25])
    foo.hyccall(123, "why", 18)
    Function.prototype.hycbind = function (thisArg, ...otherArgs) {
        thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)
        Object.defineProperty(thisArg, "fn", {
            enumerable: false,
            configurable: true,
            writable: false,
            value: this
        })
        return (...newArgs) => {
            // var allArgs = otherArgs.concat(newArgs)
            var allArgs = [...otherArgs, ...newArgs]
            thisArg.fn(...allArgs)
        }
    }
    var newFoo = foo.hycbind("abc", "hyc", 30)
    // newFoo(1.88,"广州")、
    newFoo()

ES6-ES13

es6

JS代码执行过程中需要了解的ECMA文档的术语

  • 执行上下文栈:Execution Context Stack,用于执行上下文的栈结构;
  • 执行上下文:Execution Context,代码在执行之前会先创建对应的执行上下文;
  • 变量对象:Variable Object,上下文关联的VO对象,用于记录函数和变量声明;
  • 全局对象:Global Object,全局执行上下文关联的VO对象;
  • 激活对象:Activation Object,函数执行上下文关联的VO对象;
  • 作用域链:scope chain,作用域链,用于关联指向上下文的变量查找;

let/const基本使用

ES6开始新增了两个关键字可以声明变量:let、const

  • let、const不允许重复声明变量
  • let 不会作用域提升
  • let、const在执行声明代码前是不刻意访问的

var、let、const的选择

  1. 在未来的开发中 很少会使用var 来声明变量来开发了
  2. let const 比较推荐在开发中使用
  3. 推荐优先 使用 const 保证数据的安全性不会被随意的篡改
  4. 只有需要重复赋值的时候才使用 let

模板字符串

ES6允许我们使用字符串模板来嵌入JS的变量或者表达式来进行拼接,使用 ``` `符号来编写字符串,称之为模板字符串

可以在模板字符串的时候用 ${} 来嵌入动态内容

``` ` 符号还可以调用方法自动传入参数

const name = "hyc"
const age = 18
function foo(...args){
    console.log("111",args)
}
foo `my name is ${name},age is ${age},height is ${1.88}`

函数默认值

ES6 之后 函数允许给参数一个默认值

function test(x = 10, y = 10)

可以使用这种方式来给函数的参数加入默认值,允许我们使用表达式比如

x = 1 || x > 1

Symbol的基本使用

在ES6之前,对象的属性名都是字符串形式,那么很容易造成属性名的冲突

  • 比如在新旧值同名的情况下混入 会有一个值被覆盖掉
  • 比如之前有的fn 属性 如果新添加一个fn 属性 内部原有的fn 会怎么样?

Symbol就是为了解决上面的问题,用来生成一个独一无二的值。

  1. Symbol值是通过Symbol函数来生成的,生成后可以作为属性名
  2. 在ES6中,对象的属性名可以使用字符串,也可以使用Symbol值
const s1 = Symbol()
    const s2 = Symbol()
    const obj = {
        [s1]: "aaa",
        [s2]: "aaa"
    }
    // 获取 symbol 值 对应的key
    console.log(Object.getOwnPropertySymbols(obj));

Set的基本使用

在ES6之前,我们存储数据的结构主要有两种:数组、对象。

在ES6中新增了另外两种数据结构:Set、Map,以及它们的另外形式WeakSet、WeakMap。Set 中数据是不能重复的

常用方法

set 支持for of

Set常见的属性:

  • size:返回Set中元素的个数;

Set常用的方法:

  • add(value):添加某个元素,返回Set对象本身;
  • delete(value):从set中删除和这个值相等的元素,返回boolean类型;
  • has(value):判断set中是否存在某个元素,返回boolean类型;
  • clear():清空set中所有的元素,没有返回值;
  • forEach(callback, [, thisArg]):通过forEach遍历set;
// 创建 set 
    const set1 = new Set()
    set1.add(11)
    set1.add(12)
    set1.add(13)
    set1.add(11)
    console.log(set1.size);

WeakSet使用

WeakSet和Set有什么区别

  • WeakSet 不可以遍历
  • WeakSet中只能存放对象类型,不能存放基本数据类型
  • WeakSet对元素的引用是弱引用,如果没有其他引用对某个对象进行引用,那么GC可以对该对象进行回收;
let obj1 = { name: "why" }
    let obj2 = { name: "hyc" }
    const weakset = new WeakSet()
    weakset.add(obj1)
    weakset.add(obj2)

Map基本使用

Map,用于存储映射关系

之前我们可以使用对象来存储映射关系,他们有什么区别

  • 在之前的学习中对象存储映射关系只能用字符串(ES6新增了Symbol)作为属性名(key)
  • 某些情况下我们可能希望通过其他类型作为key,比如对象,这个时候会自动将对象转成字符串来作为key;

这个时候就可以使用 map

const info = { name: "hyc" }
    const map = new Map()
    map.set(info, "aaaa")

Map的常用方法

Map常见的属性:

  • size:返回Map中元素的个数;

Map常见的方法:

  • set(key, value):在Map中添加key、value,并且返回整个Map对象;
  • get(key):根据key获取Map中的value;
  • has(key):判断是否包括某一个key,返回Boolean类型;
  • delete(key):根据key删除一个键值对,返回Boolean类型;
  • clear():清空所有的元素;
  • forEach(callback, [, thisArg]):通过forEach遍历Map;

WeakMap的使用

WeakMap,也是以键值对的形式存在的。

WeakMap和 map 的区别

  1. WeakMap的key只能使用对象,不接受其他的类型作为key;
  2. WeakMap的key对对象想的引用是弱引用
  3. WeakMap不能遍历

WeakMap常见的方法有四个:

  • set(key, value):在Map中添加key、value,并且返回整个Map对象;
  • get(key):根据key获取Map中的value;
  • has(key):判断是否包括某一个key,返回Boolean类型;
  • delete(key):根据key删除一个键值对,返回Boolean类型;

拓展知识

数值的表示

允许使用二进制 八进制来赋值

const num1  = 100
const num2  = 0b100

ES2021 新增数字过长可以用 _ 来连接

const num1 = 100_000_000
目录
相关文章
|
5月前
|
前端开发 JavaScript 开发者
JavaScript进阶-Promise与异步编程
【6月更文挑战第20天】JavaScript的Promise简化了异步操作,从ES6开始成为标准。Promise有三种状态:pending、fulfilled和rejected。基本用法涉及构造函数和`.then`处理结果,如: ```javascript new Promise((resolve, reject) => { setTimeout(resolve, 2000, '成功'); }).then(console.log); // 输出: 成功
86 4
|
5月前
|
存储 JavaScript 前端开发
JavaScript进阶-Map与Set集合
【6月更文挑战第20天】JavaScript的ES6引入了`Map`和`Set`,它们是高效处理集合数据的工具。`Map`允许任何类型的键,提供唯一键值对;`Set`存储唯一值。使用`Map`时,注意键可以非字符串,用`has`检查键存在。`Set`常用于数组去重,如`[...new Set(array)]`。了解它们的高级应用,如结构转换和高效查询,能提升代码质量。别忘了`WeakMap`用于弱引用键,防止内存泄漏。实践使用以加深理解。
77 3
|
4月前
|
XML 前端开发 JavaScript
JavaScript进阶 - AJAX请求与Fetch API
【7月更文挑战第3天】前端开发中的异步基石:AJAX与Fetch。AJAX,使用XMLHttpRequest,处理跨域、回调地狱和错误处理。Fetch,基于Promise,简化请求,但需注意默认无跨域头和HTTP错误处理。两者各有优劣,理解其问题与解决策略,能提升前端应用的性能和用户体验。
140 24
|
4月前
|
前端开发 JavaScript 安全
JavaScript进阶-JavaScript库与框架简介
【7月更文挑战第11天】JavaScript库和框架加速Web开发,但也带来挑战。选择适合项目、团队技能的库或框架,如React、Angular、Vue,是关键。保持依赖更新,注意性能优化,避免过度依赖。遵循最佳实践,确保安全性,如防XSS和CSRF。学习基础,结合代码示例(如React计数器组件),提升开发效率和应用质量。
58 1
|
4月前
|
缓存 JavaScript 前端开发
JavaScript进阶 - Web Workers与Service Worker
【7月更文挑战第4天】JavaScript的Web Workers和Service Worker增强了Web性能。Web Workers处理后台多线程,减轻主线程负担,但通信有开销,受同源策略限制。Service Worker则用于离线缓存和推送通知,需管理其生命周期、更新策略,并确保安全。两者都带来了挑战,但也极大提升了用户体验。通过理解和优化,开发者能构建更高效、安全的Web应用。
123 2
|
4月前
|
资源调度 JavaScript 前端开发
JavaScript进阶 - JavaScript库与框架简介
【7月更文挑战第5天】JavaScript库和框架构成了前端开发的核心,如jQuery简化DOM操作,Angular、React和Vue提供全面解决方案。选择时要明确需求,避免过度工程化和陡峭学习曲线。使用版本管理工具确保兼容性,持续学习以适应技术变化。示例展示了jQuery和React的简单应用。正确选择和使用这些工具,能提升开发效率并创造优秀Web应用。
49 2
|
4月前
|
设计模式 前端开发 JavaScript
JavaScript进阶 - JavaScript设计模式
【7月更文挑战第1天】JavaScript设计模式增进代码复用和维护性。单例模式确保唯一实例,用闭包防止命名冲突和控制状态访问。观察者模式实现一对多依赖,通过解绑避免内存泄漏。工厂模式封装对象创建,适度使用避免复杂度。装饰者模式动态添加行为,保持简洁以保可读性。理解模式的优缺点,灵活应用,提升代码质量。
128 3
|
4月前
|
存储 前端开发 安全
JavaScript进阶 - 浏览器存储:localStorage, sessionStorage, cookies
【7月更文挑战第2天】探索Web存储:localStorage持久化,sessionStorage会话限定,cookies则伴随HTTP请求。了解它们的特性和限制,如localStorage的5MB容量限制、跨域问题,sessionStorage的生命周期,及cookies的安全与带宽消耗。使用时需权衡安全、效率与应用场景。示例代码展示存储与检索方法。
277 2
|
5月前
|
JavaScript 前端开发
JavaScript进阶-Class与模块化编程
【6月更文挑战第21天】**ES6引入Class和模块化,提升JavaScript的代码组织和复用。Class是原型机制的语法糖,简化面向对象编程。模块化通过`import/export`管理代码,支持默认和命名导出。常见问题包括`this`指向和循环依赖。理解这些问题及避免策略,能助你写出更高效、可维护的代码。**
63 5
|
5月前
|
JavaScript 前端开发 开发者
JavaScript进阶-解构赋值与展开运算符
【6月更文挑战第19天】ES6的解构赋值与展开运算符增强了JS开发效率。解构允许直接从数组或对象提取值,简化数据提取,而展开运算符则用于合并数组和对象或作为函数参数。解构时注意设置默认值以处理不存在的属性,避免过度嵌套。展开运算符需区分数组与对象使用,勿混淆于剩余参数。通过示例展示了这两种操作在数组和对象中的应用,提升代码可读性与简洁度。
146 5