前端开发中常见的ES6技术细节分享一

news2024/11/7 12:50:51

var、let、const之间有什么区别?

var: 在ES5中,顶层对象的属性和全局变量是等价的,用var声明的变量既是全局变量,也是顶层变量​
注意:顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象

var a = 10;​
console.log(window.a) // 10

使用var声明的变量存在变量提升的情况

console.log(a) // undefined​
var a = 20

在编译阶段,编译器会将其变成以下执行

var a​
console.log(a)​
a = 20

使用var,我们能够对一个变量进行多次声明,后面声明的变量会覆盖前面的变量声明

var a = 20 ​
var a = 30​
console.log(a) // 30

在函数中使用使用var声明变量时候,该变量是局部的

var a = 20function change(){​
    var a = 30}​
change()​
console.log(a) // 20 

而如果在函数内不使用var,该变量是全局的

var a = 20function change(){​
   a = 30}​
change()​
console.log(a) // 30 

let : let是ES6新增的命令,用来声明变量​
用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效

{let a = 20}​
console.log(a) // ReferenceError: a is not defined.

不存在变量提升

console.log(a) // 报错ReferenceError​
let a = 2

这表示在声明它之前,变量a是不存在的,这时如果用到它,就会抛出一个错误​
只要块级作用域内存在let命令,这个区域就不再受外部影响

var a = 123if (true) {​
    a = 'abc' // ReferenceError​
    let a;}

使用let声明变量前,该变量都不可用,也就是大家常说的“暂时性死区”​
最后,let不允许在相同作用域中重复声明

let a = 20let a = 30​
// Uncaught SyntaxError: Identifier 'a' has already been declared

注意的是相同作用域,下面这种情况是不会报错的

let a = 20{let a = 30}

因此,我们不能在函数内部重新声明参数

function func(arg) {let arg;}​
func()​
// Uncaught SyntaxError: Identifier 'arg' has already been declared

const: const声明一个只读的常量,一旦声明,常量的值就不能改变

const a = 1​
a = 3// TypeError: Assignment to constant variable.

这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值

const a;// SyntaxError: Missing initializer in const declaration

如果之前用var或let声明过变量,再用const声明同样会报错

var a = 20let b = 20const a = 30const b = 30// 都会报错

const实际上保证的并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动​
对于简单类型的数据,值就保存在变量指向的那个内存地址,因此等同于常量​
对于复杂类型的数据,变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的,并不能确保改变量的结构不变

const foo = {};​
​
// 为 foo 添加一个属性,可以成功​
foo.prop = 123;​
foo.prop // 123​// 将 foo 指向另一个对象,就会报错​
foo = {}; // TypeError: "foo" is read-only

使用区别:
var、let、const三者区别可以围绕下面五点展开:​

  • 变量提升​
  • 暂时性死区​
  • 块级作用域​
  • 重复声明​
  • 修改声明的变量​
  • 使用

变量提升​
var 声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined​
// 2023.4.25 更新​
let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错​
let / const 不存在变量提升是不完全正确的,只能说由于暂时性死区的存在使得我们无法直观感受到变量提升的效果。​
let 和 const 定义的变量都会被提升,但是不会被初始化,不能被引用,不会像var定义的变量那样,初始值为undefined。​
当进入let变量的作用域时,会立即给它创建存储空间,但是不会对它进行初始化。​
变量的赋值可以分为三个阶段:

  • 创建变量,在内存中开辟空间​
  • 初始化变量,将变量初始化为undefined​
  • 真正赋值

关于let、var和function:​

  • let 的「创建」过程被提升了,但是初始化没有提升。​
  • var 的「创建」和「初始化」都被提升了。​
  • function 的「创建」「初始化」和「赋值」都被提升了。
// var​
console.log(a)  // undefined​
var a = 10​
​
// let ​
console.log(b)  // Cannot access 'b' before initialization​
let b = 10​
​
// const​
console.log(c)  // Cannot access 'c' before initialization​
const c = 10

暂时性死区​
var不存在暂时性死区​
let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量

// var​
console.log(a)  // undefined​
var a = 10​
​
// let​
console.log(b)  // Cannot access 'b' before initialization​
let b = 10​
​
// const​
console.log(c)  // Cannot access 'c' before initialization​
const c = 10

块级作用域​
var不存在块级作用域​
let和const存在块级作用域

// var​
{var a = 20}​
console.log(a)  // 20​// let​
{let b = 20}​
console.log(b)  // Uncaught ReferenceError: b is not defined​// const​
{const c = 20}​
console.log(c)  // Uncaught ReferenceError: c is not defined

重复声明
var允许重复声明变量​
let和const在同一作用域不允许重复声明变量

// var​
var a = 10​
var a = 20 // 20​
​
// let​
let b = 10let b = 20 // Identifier 'b' has already been declared​
​
// const​
const c = 10​
const c = 20 // Identifier 'c' has already been declared

修改声明的变量

// var​
var a = 10​
a = 20​
console.log(a)  // 20​
​
//let​
let b = 10​
b = 20​
console.log(b)  // 20​
​
// const​
const c = 10​
c = 20​
console.log(c) // Uncaught TypeError: Assignment to constant variable

使用​
能用const的情况尽量使用const,其他情况下大多数使用let,避免使用var

ES6新特性

关于ES6和JavaScript的关系​
1、ES6是对于ES2015+的俗称,也可以说是通常叫法,那么,ES6是什么呢?​
ES 全称是ECMAScript,它是JavaScript基础构建的一种语言,JavaScript正是建立在ECMAScript语言的基础规范中建立使用的,那么,ECMAScript的使用,对于JavaScript至关重要!​
在我的理解中,ECMAScript是一种语言层面的东西,它只是定义了JavaScript以及在它基础之上建立的其他语言的语法规范,而JavaScript的语言,更关于一种平台性质在其中。​
JavaScript包括 ECMAScript、DOM、BOM三个组成部分,DOM和BOM是web API提供的接口或者是JavaScript和浏览器之间进行交互的部分,实质就是操纵文档元素,进行展示布局,而ECMAScript在JavaScript中其中语法的作用,它不会去跟文档有直接的关系,但是他的数据处理完成后会通过web API展示在文档中。​
ES6新特性的分类​
新特性主要归为四大类:​

  • 解决原有语法上的一些不足​
    比如let 和 const 的块级作用域​
  • 对原有语法进行增强​
    比如解构、展开、参数默认值、模板字符串​
  • 全新的对象、全新的方法、全新的功能​
    比如promise、proxy、object的assign、is​
  • 全新的数据类型和数据结构​
    比如symbol、set、map

1. let、const 块级作用域以及和 var 的区别 可参考上边的描述

2.解构-快速提取数组/对象中的元素

  • 数组解构​
  • 单独解构-根据数组索引,将数组解构成单独的元素
const arr = [1, 2, 3]​
​
const [a, b, c] = arr​
console.log(a, b, c) //1,2,3​
const [, , d] = arr​
console.log(d) //3

默认值,解构时可以给变量设置默认值,数组没有这个元素的话

const arr = [1, 2, 3]​
​
const [, , , defaultVal = '4'] = arr​
console.log('设置默认值', defaultVal)

剩余解构-用 “…+变量名” 解构剩余参数到新数组,只能用一次

const arr = [1, 2, 3]​
​
const [e, ...rest] = arr​
console.log(rest) //[2, 3]

实例应用

// 拆分字符串​
const str = 'xiaobai/18/200'const strArr = str.split('/')const [, age] = strArr​
console.log(age) //18

对象解构​

  • 单个/多个解构-跟数组解构差不多
const obj = { name: 'xiaohui', age: 18, height: undefined }const { name, age } = obj​
console.log(name, age) // 'xiaohui', 18

解构+重命名-给解构出来的变量重命名

const obj = { name: 'xiaohui', age: 18, height: undefined }const { name: objName } = obj​
console.log(objName)

默认值-给解构变量设置默认值

const obj = { name: 'xiaohui', age: 18, height: undefined }​
const { next = 'default' } = obj​
console.log(next)

3.模板字符串
用法:使用``将字符串包裹起来​
功能:可以换行、插值、使用标签函数进行字符串操作​
示例:

  • 换行/插值
//换行​
const str = `fdsjak​
    fdsa`​
console.log(str)​
​
// 插值​
const strs = `random: ${Math.random()}`​
console.log(strs)

标签函数-可以对模板字符串的字符串和插值进行处理和过滤等操作

/**​
 * 字符串模板函数​
 * @param {array} strs 以插值为分隔符组成的字符串数组​
 * @param {string} name 插值的value,有多少个就会传入多少个​
 */const tagFunc = (strs, name, gender) => {const [str1, str2, str3] = strs​
  const genderParsed = gender == '1' ? '男' : '女'// 可以在此做过滤,字符串处理,多语言等操作​
  return str1 + name + str2 + str3 + genderParsed​
0-0-0-}​
​
// 带标签的模板字符串,​
const person = {​
  name: 'xiaohui',​
  gender: 1,}// 返回值为标签函数的返回值​
const result = tagFunc`my name is ${person.name}.gender is ${person.gender}`​
console.log(result) //my name is xiaohui.gender is 男

4. 字符串扩展方法​

  • includes-是否包含​
  • startsWith-是否以什么开始​
  • endsWith-是否以什么结束
const str = 'abcd'​
​
console.log(str.includes('e')) //false​
console.log(str.startsWith('a')) //true​
console.log(str.endsWith('a')) //false

5.参数默认值&剩余参数
给函数形参设置默认值

// 带默认参数的形参一般放在后面,减少传参导致的错误几率​
const defaultParams = function (name, age = 0) {return [age, name]}​
console.log(defaultParams(1))

使用…rest 形式设置剩余形参,支持无限参数

// 剩余参数,转化成数组​
const restParams = function (...args) {​
  console.log(args.toString()) //1, 2, 3, 4, 5}​
​
restParams(1, 2, 3, 4, 5)

6.展开数组

const arr = [1, 2, 3]​
​
console.log(...arr)// 等价于es5中以下写法​
console.log.apply(console, arr)

7.箭头函数
特性&优势:​
1、简化了函数的写法​
2、没有 this 机制,this 继承自上一个函数的上下文,如果上一层没有函数,则指向 window​
3、作为异步回调函数时,可解决 this 指向问题

const inc = (n) => n + 1​
console.log(inc(100))​
​
const obj = {​
  name: 'aa',func() {setTimeout(() => {​
      console.log(this.name) //aa​
    }, 0)setTimeout(function () {​
      console.log(this.name) //undefined​
    }, 0)},}​
obj.func()

8.对象字面量增强

  • 同名属性可以省略 key:value 形式,直接 key,​
  • 函数可以省略 key:value 形式​
  • 可以直接 func(),​
  • 可以使用计算属性,比如:{[Math.random()]: value}
/**​
 * 1、增强了对象字面量:​
 * 1,同名属性可以省略key:value形式,直接key,​
 * 2,函数可以省略key:value形式​
 * 3,可以直接func(),​
 * 4,可以使用计算属性,比如:{[Math.random()]: value}​
 */const arr = [1, 2, 3]const obj = {​
  arr,func() {​
    console.log(this.arr)},[Math.random()]: arr,}​
​
console.log(obj)

9.Object.assign(target1, target2, targetN)-复制/合并对象

/**​
 * Object.assign(target1, target2, ...targetn)​
 * 后面的属性向前面的属性合并​
 * 如果target1是空对象,可以创建一个全新对象,而不是对象引用​
 */const obj1 = {​
  a: 1,​
  b: 2,}const obj2 = {​
  a: 1,​
  b: 2,}​
​
const obj3 = Object.assign({}, obj1)​
obj3.a = 5​
console.log(obj3, obj2, obj1)

10.Object.is(value1, value2)​
作用:比较两个值是否相等

console.log(NaN === NaN) //false​
console.log(Object.is(NaN, NaN)) //true​
console.log(0 === -0) // true​
console.log(Object.is(0, -0)) //false​
console.log(Object.is(1, 1)) //true

11.Proxy(object, handler)
作用:​

  • 代理一个对象的所有,包括读写操作和各种操作的监听​

用法:

const P = {​
  n: 'p',​
  a: 19,}​
​
const proxy = new Proxy(P, {get(target, property) {​
    console.log(target, property)return property in target ? target[property] : null},defineProperty(target, property, attrs) {​
    console.log(target, property, attrs)//   throw new Error('不允许修改')​
  },deleteProperty(target, property) {​
    console.log(target, property)delete target[property]},set(target, property, value) {​
    target[property] = value​
  },})​
​
proxy.c = 100​
console.log('pp', P)

优势:​
拥有很多 defineProperty 没有的属性方法,比如:​

  • handler.getPrototypeOf() —Object.getPrototypeOf 方法的监听器​
  • handler.setPrototypeOf() —Object.setPrototypeOf 方法的监听器。​
  • handler.isExtensible() —Object.isExtensible 方法的监听器。​
  • handler.preventExtensions() —Object.preventExtensions 方法的监听器。​
  • handler.getOwnPropertyDescriptor() —Object.getOwnPropertyDescriptor 方法的监听器。​
  • handler.defineProperty() —Object.defineProperty 方法的监听器。​
  • handler.has() —in 操作符的监听器。​
  • handler.get() —属性读取操作的监听器。​
  • handler.set() —属性设置操作的监听器。​
  • handler.deleteProperty() —delete 操作符的监听器​
  • handler.ownKeys() —Object.getOwnPropertyNames 方法和 Object.getOwnPropertySymbols 方法的监听器。​
  • handler.apply() —函数调用操作的监听器。​
  • handler.construct() —new 操作符的监听器。​
    对数组的监视更方便​
    以非侵入的方式监管对象的读写

12.Reflect
作用:​
集成 Object 操作的所有方法,统一、方便,具体方法如下:​
用于对对象的统一操作,集成 Object 相关的所有方法​
1、apply:类似 Function.prototype.apply​
2、Reflect.construct()​
对构造函数进行 new 操作,相当于执行 new target(…args)。​
3、Reflect.defineProperty()​
和 Object.defineProperty() 类似。​
4、Reflect.deleteProperty()​
作为函数的 delete 操作符,相当于执行 delete target[name]。​
5、Reflect.get()​
获取对象身上某个属性的值,类似于 target[name]。​
6、Reflect.getOwnPropertyDescriptor()​
类似于 Object.getOwnPropertyDescriptor()。​
7、Reflect.getPrototypeOf()​
类似于 Object.getPrototypeOf(), 获取目标对象的原型。​
8、Reflect.has()​
判断一个对象是否存在某个属性,和 in 运算符 的功能完全相同。​
9、Reflect.isExtensible()​
类似于 Object.isExtensible().判断对象是否可扩展,可以添加额外属性​
Object.seal(封闭对象), Object.freeze(冻结对象)是不可扩展的​
10、Reflect.ownKeys()​
返回一个包含所有自身属性(不包含继承属性)的数组。(类似于 Object.keys(), 但不会受 enumerable 影响).​
11、Reflect.preventExtensions()​
类似于 Object.preventExtensions()。返回一个 Boolean。​
12、Reflect.set()​
将值分配给属性的函数。返回一个 Boolean,如果更新成功,则返回 true, 反之返回 false。​
13、Reflect.setPrototypeOf()​
类似于 Object.setPrototypeOf()。

const obj = {​
  name: 'reflect',}​
Reflect.preventExtensions(obj) //禁止扩展​
console.log(Reflect.set(obj, 'age', 'xiaobai')) //false​
console.log(obj) //{ name: 'reflect' }​
console.log(Reflect.isExtensible(obj, 'name')) //false​
console.log(Reflect.ownKeys(obj)) //[ 'name' ]

13.Promise

14.class&静态方法&继承
使用 class 关键字定义类

class Person {constructor(props) {this.props = props​
  }}

方法​

  • 实例方法,需要实例化之后才能调用,this 指向实例​
  • 静态方法,用 static 修饰符修饰,可以直接通过类名调用,不需要实例化,this 不指向实例,而是指向当前类
class Person {constructor(props) {this.props = props​
  }// 实例方法​
  eat() {}// 静态方法​
  static run() {}}// 调用静态方法​
Person.run()const person = new Person('props')// 调用实例方法​
person.eat()

继承:子类使用 extends 关键字实现继承,可以继承父类所有属性

class Student extends Person {constructor(props) {super(props)}printProps() {​
    console.log(this.props)}}​
​
const student = new Student('student')​
student.printProps()

15.Set
说明:​
Set 是一种类似于数组的数据结构​
特性:​

  • 元素唯一性,不允许重复元素​
  • 使用 add 增加重复元素,将会被忽略​

用途:​

  • 数组去重​
  • 数据存储
const arr = [1, 3, 1, 1, 1]const set = new Set(arr)​
set.add(1).add(1)​
console.log(set.size) //2​
const newArr = Array.from(set)​
console.log(newArr) //[ 1, 3 ]

16.Map
说明:​
类似 Object,以 key、value 形式存储数据​
区别:​
Map 键不会隐式转换成字符串,而是保持原有类型​
实例:

const map = new Map()​
map.set(1, 1)​
map.set('name', 'map')​
map.set(obj, obj)​
console.log(map.get(1)) //1​
/**​
        1 1​
        name map​
        { '1': 1, true: true, a: 'a' } { '1': 1, true: true, a: 'a' }​
     */​
map.forEach((val, key) => {​
  console.log(key, val)})

17.Symbol
说明:​
JavaScript 第六种原始数据类型,用来定义一个唯一的变量​
作用:​
创建唯一的变量,解决对象键名重复问题​
为对象、类、函数等创建私有属性​
修改对象的 toString 标签​
为对象添加迭代器属性​
如何获取对象的 symbol 属性?​
Object.getOwnPropertySymbols(object)​
实例

// 对象属性重名问题;​
const objSymbol = {[Symbol()]: 1,[Symbol()]: 2,}​
console.log(objSymbol)​
​
// 2、为对象、类、函数等创建私有属性​
const name = Symbol()const obj2 = {[name]: 'symbol',testPrivate() {​
    console.log(this[name])},}​
​
obj2.testPrivate()// 定义toString标签;​
console.log(obj2.toString())​
obj2[Symbol.toStringTag] = 'xx'​
console.log(obj2.toString()) //[object xx]

18.for…of…
用途:​
已统一的方式,遍历所有引用数据类型​
特性:​
可以随时使用 break 终止遍历,而 forEach 不行​
实例:

// 基本用法​
// 遍历数组​
  if (item > 2) {​
    console.log(item)}}​
​
// 遍历set​
const set = new Set()​
set.add('foo').add('bar')for (const item of set) {​
  console.log('set for of', item)}// 遍历map​
const map = new Map()​
map.set('foo', 'one').set('bar', 'two')for (const [key, val] of map) {​
  console.log('for of map', key, val)}//迭代对象​
const obj = {​
  name: 'xiaohui',​
  age: '10',​
  store: [1, 2, 3],// 实现可迭代的接口​
  [Symbol.iterator]: function () {const params = [this.name, this.age, this.store]let index = 0return {next() {const ret = {​
          value: params[index],​
          done: index >= params.length,}​
        index++return ret​
      },}},}​
​
for (const item of obj) {​
  console.log('obj for of', item)}

19.迭代器模式
作用:通过 Symbol.interator 对外提供统一的接口,获取内部的数据​
外部可以通过 for…of…去迭代内部的数据

const tods = {​
  life: ['eat', 'sleep'],​
  learn: ['js', 'dart'],// 增加的任务​
  work: ['sale', 'customer'],[Symbol.iterator]: function () {const all = []​
    Object.keys(this).forEach((key) => {​
      all.push(...this[key])})let index = 0return {next() {const ret = {​
          value: all[index],​
          done: index >= all.length,}​
        index++return ret​
      },}},}​
​
for (const item of tods) {​
  console.log(item)}

20.Generator 生成器
Generator​

  • 函数前添加 *,生成一个生成器​
  • 一般配合 yield 关键字使用​
  • 最大特点,惰性执行,调 next 才会往下执行​
  • 主要用来解决异步回调过深的问题
// 生成迭代器方法​
//  生成器Generator的应用​function* createIdGenerator() {let id = 1while (id < 3) yield id++}const createId = createIdGenerator()​
console.log(createId.next()) //{ value: 1, done: false }​
console.log(createId.next()) //{ value: 2, done: false }​
console.log(createId.next()) //{ value: undefined, done: true }​const todos = {​
  life: ['eat', 'sleep', 'baba'],​
  learn: ['es5', 'es6', 'design pattern'],​
  work: ['b', 'c', 'framework'],[Symbol.iterator]: function* () {const all = [...this.life, ...this.learn, ...this.work]for (const i of all) {yield i​
    }},}for (const item of todos) {​
  console.log(item)}

21.includes 函数-es2016
判断数组是否包含某个元素,包含 NaN,解决 indexOf 无法查找 NaN 问题

//  includes函数​
const arr = ['foo', 'bar', 'baz', NaN]​
console.log(arr.includes(NaN)) //true​
console.log(arr.indexOf(NaN)) //-1

22.运算符-es2016

// 指数运算符 **​
// es5中2十次方​
console.log(Math.pow(2, 10))// es6中2十次方​
console.log(2 ** 10)

23.values 函数-es2017
将对象的值以数组的形式返回

const obj = {​
  foo: 1,​
  bar: 2,​
  baz: 3,}​
​
console.log(Object.values(obj)) //[ 1, 2, 3 ]

24.entries 函数-es2017
将对象以键值对二维数组返回,使之可以使用 for…of…遍历

const obj = {​
  foo: 1,​
  bar: 2,​
  baz: 3,}​
console.log(Object.entries(obj))const entry = Object.entries(obj)for (const [key, value] of entry) {​
  console.log(key, value)}

25.Object.getOwnPropertyDescriptors(obj)-es2017
获取对象的描述信息​
可以通过获得的描述信息,配合 Object.defineProperties 来完整复制对象,包含 get,set 方法

// getOwnPropertyDescriptors​// 普通get方法​
const objGet = {​
  foo: 1,​
  bar: 2,get getCount() {return this.foo + this.bar​
  },}// assign方法会把getCount当做普通属性复制,从而getCount为3,修改bar不管用​
const objGet1 = Object.assign({}, objGet)​
objGet1.bar = 3​
console.log(objGet1.getCount) //3​
// descriptors​
const descriptors = Object.getOwnPropertyDescriptors(objGet)​
console.log('des', descriptors)// 通过descriptors来复制对象,可以完整复制对象,包含get,set​
const objGet2 = Object.defineProperties({}, descriptors)​
objGet2.bar = 3​
console.log(objGet2.getCount) //4

26.padStart, padEnd 函数-es2017
在字符串前,或者后面追加指定字符串​
参数:​
targetLenght: 填充后的目标长度​
padString:填充的字符串​
规则:​
1、填充的字符串超过目标长度,会在规定长度时被截断​
2、填充字符串太短会以空格填充​
3、padString 未传值,以空格填充​
作用:​
一般用来对齐字符串输出

 /**​
     *  foo.................|1​
        barbar..............|2​
        bazbazbaz...........|3​
     */​
    console.log(`${key.padEnd(20, '.')}${value.toString().padStart(2, '|')}`)

基本数据类型

JavaScript 中的简单数据类型包括以下几种:​

  • 字符串(String):用于表示文本数据,用引号(单引号或双引号)包裹起来,例如:“Hello, World!”。​
  • 数字(Number):用于表示数值数据,包括整数和浮点数(带小数点的数),例如:42、3.14。​
  • 布尔值(Boolean):用于表示逻辑值,只有两个可能的取值:true(真)和false(假)。​
  • undefined:表示未定义的值,通常表示未声明的变量或缺少返回值的函数。​
  • null:表示空值,用于显式地表示变量或对象没有值。​
  • Symbol(符号):表示唯一的标识符,用于对象属性的键。​
  • BigInt:用于表示任意精度的整数。BigInt 是一种简单数据类型,在 ECMAScript 2020 中引入。​

这些简单数据类型在 JavaScript 中是不可变的,也就是说,它们的值在创建后不能被修改。当你对一个简单数据类型的值进行操作时,实际上是创建了一个新的值。

ES6中数组扩展

扩展运算符(Spread operator):使用 … 语法可以将一个数组展开成多个独立的元素,或者将多个元素合并为一个数组。​

  • Array.from():通过类似数组的对象或可迭代对象创建一个新的数组。​
  • Array.of():创建一个由传入参数组成的新数组。​
  • find() 和 findIndex():用于在数组中查找满足指定条件的第一个元素及其索引。​
  • includes():检查数组是否包含指定的元素,并返回布尔值。​
  • fill():使用指定的值填充数组的所有元素。​
  • flat() 和 flatMap():用于将嵌套的数组展平,减少维度。​
  • map()、filter()、reduce()、forEach() 等方法的回调函数支持箭头函数语法。​
  • entries()、keys() 和 values():用于遍历数组的键值对、键和值。​
  • 数组解构赋值:可以通过解构赋值从数组中提取值并赋给变量。​
  • 数组的扩展属性:Array.prototype.length 可以被修改,- Array.prototype[@@toStringTag] 返回 “Array”。

箭头函数

什么是箭头函数?​
ES6中允许使用箭头=>来定义箭头函数,具体语法,我们来看一个简单的例子:

// 箭头函数​
let fun = (name) => {// 函数体​
    return `Hello ${name} !`;};​
​
// 等同于​
let fun = function (name) {// 函数体​
    return `Hello ${name} !`;};

可以看出,定义箭头函在数语法上要比普通函数简洁得多。箭头函数省去了function关键字,采用箭头=>来定义函数。函数的参数放在=>前面的括号中,函数体跟在=>后的花括号中。

箭头函数与普通函数的区别​

1、语法更加简洁、清晰​
从上面的基本语法示例中可以看出,箭头函数的定义要比普通函数定义简洁、清晰得多,很快捷。​
2、箭头函数不会创建自己的this(重要!!深入理解!!)​
我们先来看看MDN上对箭头函数this的解释。​

箭头函数不会创建自己的this,所以它没有自己的this,它只会从自己的作用域链的上一层继承this。​
​箭头函数没有自己的this,它会捕获自己在定义时(注意,是定义时,不是调用时)所处的外层执行环境的this,并继承这个this值。所以,箭头函数中this的指向在它被定义的时候就已经确定了,之后永远不会改变。

3、箭头函数继承而来的this指向永远不变(重要)
上面的例子,就完全可以说明箭头函数继承而来的this指向永远不变。对象obj的方法b是使用箭头函数定义的,这个函数中的this就永远指向它定义时所处的全局执行环境中的this,即便这个函数是作为对象obj的方法调用,this依旧指向Window对象。

4、.call()/.apply()/.bind()无法改变箭头函数中this的指向
.call()/.apply()/.bind()方法可以用来动态修改函数执行时this的指向,但由于箭头函数的this定义时就已经确定且永远不会改变。所以使用这些方法永远也改变不了箭头函数this的指向,虽然这么做代码不会报错

5、箭头函数不能作为构造函数使用
我们先了解一下构造函数的new都做了些什么?简单来说,分为四步:​
① JS内部首先会先生成一个对象; ② 再把函数中的this指向该对象; ③ 然后执行构造函数中的语句; ④ 最终返回该对象实例。​
但是!!因为箭头函数没有自己的this,它的this其实是继承了外层执行环境中的this,且this指向永远不会随在哪里调用、被谁调用而改变,所以箭头函数不能作为构造函数使用,或者说构造函数不能定义成箭头函数,否则用new调用时会报错!

6、箭头函数没有自己的arguments
箭头函数没有自己的arguments对象。在箭头函数中访问arguments实际上获得的是外层局部(函数)执行环境中的值。

7、箭头函数没有原型prototype

let sayHi = () => {​
    console.log('Hello World !')};​
console.log(sayHi.prototype); // undefined

8、箭头函数不能用作Generator函数,不能使用yeild关键字

symbol 有什么用处?

ES5 的对象属性名都是字符串,这容易造成属性名的冲突。比如,你使用了一个他人提供的对象,但又想为这个对象添加新的方法(mixin 模式),新方法的名字就有可能与现有方法产生冲突。如果有一种机制,保证每个属性的名字都是独一无二的就好了,这样就从根本上防止属性名的冲突。这就是 ES6 引入Symbol的原因。​
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。​
Symbol 值通过Symbol函数生成。这就是说,对象的属性名现在可以有两种类型,一种是原来就有的字符串,另一种就是新增的 Symbol 类型。凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。

async/await 和 Promise 有什么关系?

Promise​

Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步操作的成功和失败分别绑定相应的处理方法(handlers)。 这让异步方法可以像同步方法那样返回值,但并不是立即返回最终执行结果,而是一个能代表未来出现的结果的promise对象​

async/await​
es2017的新语法,async/await就是generator + promise的语法糖​
async/await 和 Promise 的关系非常的巧妙,await必须在async内使用,并装饰一个Promise对象,async返回的也是一个Promise对象。​
async/await中的return/throw会代理自己返回的Promise的resolve/reject,而一个Promise的resolve/reject会使得await得到返回值或抛出异常。​

  • 如果方法内无await节点​
    return 一个字面量则会得到一个{PromiseStatus: resolved}的Promise。​
    throw 一个Error则会得到一个{PromiseStatus: rejected}的Promise。​
  • 如果方法内有await节点​
    async会返回一个{PromiseStatus: pending}的Promise(发生切换,异步等待Promise的执行结果)。​
    Promise的resolve会使得await的代码节点获得相应的返回结果,并继续向下执行。​
    Promise的reject 会使得await的代码节点自动抛出相应的异常,终止向下继续执行。

如何中断Promise

Promise 有个缺点就是一旦创建就无法取消,所以本质上 Promise 是无法被终止的,但我们在开发过程中可能会遇到下面两个需求

  • 中断调用链
    就是在某个 then/catch 执行之后,不想让后续的链式调用继续执行了
somePromise​
  .then(() => {}).then(() => {// 终止 Promise 链,让下面的 then、catch 和 finally 都不执行​
  }).then(() => console.log('then')).catch(() => console.log('catch')).finally(() => console.log('finally'))

​一种方法是在then中直接抛错, 这样就不会执行后面的then, 直接跳到catch方法打印err(但此方法并没有实际中断)。但如果链路中对错误进行了捕获,后面的then函数还是会继续执行。​
Promise的then方法接收两个参数:

Promise.prototype.then(onFulfilled, onRejected)

若onFulfilled或onRejected是一个函数,当函数返回一个新Promise对象时,原Promise对象的状态将跟新对象保持一致,详见Promises/A+标准。​
因此,当新对象保持“pending”状态时,原Promise链将会中止执行。

Promise.resolve().then(() => {​
    console.log('then 1')return new Promise(() => {})}).then(() => {​
    console.log('then 2')}).then(() => {​
    console.log('then 3')}).catch((err) => {​
    console.log(err)})
  • 中断Promise
    注意这里是中断而不是终止,因为 Promise 无法终止,这个中断的意思是:在合适的时候,把 pending 状态的 promise 给 reject 掉。例如一个常见的应用场景就是希望给网络请求设置超时时间,一旦超时就就中断,我们这里用定时器模拟一个网络请求,随机 3 秒之内返回。
function timeoutWrapper(p, timeout = 2000) {const wait = new Promise((resolve, reject) => {setTimeout(() => {reject('请求超时')}, timeout)})return Promise.race([p, wait])}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2235019.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5G智能对讲终端|北斗有源终端|北斗手持机|单兵|单北斗

在当今这个快速发展的数字化时代&#xff0c;5G技术的广泛应用正以前所未有的速度推动着各行各业的变革。作为这一技术浪潮中的重要一环&#xff0c;5G智能终端QM630D凭借其卓越的性能和多样化的功能&#xff0c;在林业、渔业、安保、电力、交通等多个领域展现出了巨大的应用潜…

【comfyui教程】ComfyUI有趣工作流推荐:快速换脸,创意随手掌握!

前言 在数字影像处理和创意表达领域&#xff0c;ComfyUI 绝对是你的得力助手&#xff01;今天我们推荐一个非常有趣的工作流——快速换脸。无论你是图像编辑小白&#xff0c;还是深耕AI影像的达人&#xff0c;这个工作流都能让你快速实现面部迁移&#xff0c;体验全新的照片玩…

GPT原理;ChatGPT 等类似的问答系统工作流程如下;当用户向 ChatGPT 输入一个问题后:举例说明;ChatGPT不是通过索引搜索的传统知识库

目录 GPT原理 GPT架构 GPT 主要基于 Transformer 的解码器部分 ChatGPT 等类似的问答系统工作流程如下: 用户输入 文本预处理 模型处理 答案生成 输出回答 当用户向 ChatGPT 输入一个问题后:举例说明 文本预处理: ChatGPT不是通过索引搜索的传统知识库 GPT GPT…

Linux云计算 |【第五阶段】CLOUD-DAY8

主要内容&#xff1a; 掌握DaemonSet控制器、污点策略&#xff08;NoSchedule、Noexecute&#xff09;、Job / CronJob资源对象、掌握Service服务、服务名解析CluterIP&#xff08;服务名自动发现&#xff09;、&#xff08;Nodeport、Headless&#xff09;、Ingress控制器 一…

基于Zynq FPGA对雷龙SD NAND的测试

一、SD NAND 特征 1.1 SD 卡简介 雷龙的 SD NAND 有很多型号&#xff0c;在测试中使用的是 CSNP4GCR01-AMW 与 CSNP32GCR01-AOW。芯片是基于 NAND FLASH 和 SD 控制器实现的 SD 卡。具有强大的坏块管理和纠错功能&#xff0c;并且在意外掉电的情况下同样能保证数据的安全。 …

探索空间计算与 VR 设备的未来:4K4DGen 高分辨率全景 4D 内容生成系统

在当今科技飞速发展的时代,空间计算和 VR 设备正逐渐成为人们体验沉浸式场景的重要工具。而今天,我们要为大家介绍一款具有创新性的技术 ——4K4DGen 高分辨率全景 4D 内容生成系统,它为 VR/AR 沉浸式体验带来了全新的可能性。 一、项目概述 4K4DGen 项目的核心目标是实现 …

使用官网tar包制作OpenSSL及OpenSSH rpm包进行升级安装(OpenSSH_9.9p1, without OpenSSL未解决)

一、制作openssl-1.1.1w.rpm包 1、安装基础依赖包和rpmbuild及其依赖包 yum install curl which make gcc perl perl-WWW-Curl rpm-build rpm-build rpmdevtools tree -y yum install gcc-c glibc glibc-devel openssl openssl-devel \pcre-devel zlib zlib-devel perl…

Node.js回调函数以及事件循环使用介绍(基础介绍 三)

回调函数 Node.js 异步编程的直接体现就是回调。 异步编程依托于回调来实现&#xff0c;但不能说使用了回调后程序就异步化了。 回调函数在完成任务后就会被调用&#xff0c;Node 使用了大量的回调函数&#xff0c;Node 所有 API 都支持回调函数。 例如&#xff0c;我们可以…

Linux(CentOS)安装 MySQL

CentOS版本&#xff1a;CentOS 7 MySQL版本&#xff1a;MySQL Community Server 8.4.3 LTS 1、下载 MySQL 打开MySQL官网&#xff1a;https://www.mysql.com/ 直接下载网址&#xff1a;https://dev.mysql.com/downloads/mysql/ 其他版本 2、上传 MySQL 文件到 CentOS 使用F…

服务器被攻击排查记录

起因 我的深度学习的所有进程突然被killed&#xff0c;我以为是检修&#xff0c;后面发现好像简单的python代码可以正常运行。但是我的训练进程一启动就会被killed 第一时间没有用htop查看cpu&#xff0c;用top看着挺正常的&#xff0c;但是后面看htop&#xff0c;全是绿的&a…

TDengine 签约蘑菇物联,改造通用设备工业互联网平台

在当前工业互联网迅猛发展的背景下&#xff0c;企业面临着日益增长的数据处理需求和智能化转型的挑战。通用工业设备的高能耗问题愈发突出&#xff0c;尤其是由这些设备组成的公辅能源车间&#xff0c;亟需更高效的解决方案来提升设备运行效率&#xff0c;降低能源消耗。为此&a…

【大数据学习 | kafka高级部分】文件清除原理

2. 两种文件清除策略 kafka数据并不是为了做大量存储使用的&#xff0c;主要的功能是在流式计算中进行数据的流转&#xff0c;所以kafka中的数据并不做长期存储&#xff0c;默认存储时间为7天 那么问题来了&#xff0c;kafka中的数据是如何进行删除的呢&#xff1f; 在Kafka…

TOEIC 词汇专题:市场销售篇

TOEIC 词汇专题&#xff1a;市场销售篇 市场销售是企业推广产品和树立品牌形象的重要环节。今天为大家介绍在市场销售领域中常用的托业词汇&#xff0c;助力更好地理解相关英语场景。 1. 市场推广与活动 市场销售离不开推广活动&#xff0c;以下是一些核心词汇&#xff1a; A…

基于 Vue3、Vite 和 TypeScript 实现开发环境下解决跨域问题,实现前后端数据传递

引言 本文介绍如何在开发环境下解决 Vite 前端&#xff08;端口 3000&#xff09;和后端&#xff08;端口 80&#xff09;之间的跨域问题&#xff1a; 在开发环境中&#xff0c;前端使用的 Vite 端口与后端端口不一致&#xff0c;会产生跨域错误提示&#xff1a; Access to X…

OpenCV-Python-安装环境与测试样例

本文使用Pycharm安装openCV 1.打开pycharm终端 (GUI是我自己创建的项目名称) 错误&#xff1a;终端如果打开闪退的话 应对如下&#xff1a; 汉化版&#xff1a;文件->设置->工具->终端->红框位置设置cmd 英文版&#xff1a;file->settings->Tools->t…

Spark on YARN:Spark集群模式之Yarn模式的原理、搭建与实践

Spark 的介绍与搭建&#xff1a;从理论到实践-CSDN博客 Spark 的Standalone集群环境安装与测试-CSDN博客 PySpark 本地开发环境搭建与实践-CSDN博客 Spark 程序开发与提交&#xff1a;本地与集群模式全解析-CSDN博客 目录 一、Spark on YARN 的优势 &#xff08;一&#…

基于IM场景下的Wasm初探:提升Web应用性能|得物技术

一、何为Wasm &#xff1f; Wasm&#xff0c;全称 WebAssembly&#xff0c;官网描述是一种用于基于堆栈的虚拟机的二进制指令格式。Wasm被设计为一个可移植的目标&#xff0c;用于编译C/C/Rust等高级语言&#xff0c;支持在Web上部署客户端和服务器应用程序。 Wasm 的开发者参…

【JAVA毕业设计】基于Vue和SpringBoot的墙绘产品展示交易平台

本文项目编号 T 049 &#xff0c;文末自助获取源码 \color{red}{T049&#xff0c;文末自助获取源码} T049&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

在全域数据整合过程中,如何确保数据的一致性和准确性

在全域数据整合过程中&#xff0c;确保数据的一致性和准确性是至关重要的&#xff0c;这不仅关系到数据分析结果的可靠性&#xff0c;还直接影响到企业决策的科学性和有效性。Aloudata AIR 逻辑数据编织平台通过数据虚拟化技术&#xff0c;为这一过程提供了强有力的支持。以下是…

w024基于SpringBoot的企业客户管理系统的设计与实现

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0…