前端开发中常见的ES6技术细节分享一
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 = 20
function change(){var a = 30
}
change()
console.log(a) // 20
而如果在函数内不使用var,该变量是全局的
var a = 20
function 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 = 123
if (true) {a = 'abc' // ReferenceErrorlet a;
}
使用let声明变量前,该变量都不可用,也就是大家常说的“暂时性死区”
最后,let不允许在相同作用域中重复声明
let a = 20
let 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 = 20
let b = 20
const a = 30
const 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 = 10
let 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 = `fdsjakfdsa`
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] = strsconst 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 1name 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.................|1barbar..............|2bazbazbaz...........|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])
}
相关文章:
前端开发中常见的ES6技术细节分享一
var、let、const之间有什么区别? var: 在ES5中,顶层对象的属性和全局变量是等价的,用var声明的变量既是全局变量,也是顶层变量 注意:顶层对象,在浏览器环境指的是window对象,在 Node 指的是g…...
行业类别-智慧城市-子类别智能交通-细分类别自动驾驶技术-应用场景城市公共交通优化
1.大纲分析 针对题目“8.0 行业类别-智慧城市-子类别智能交通-细分类别自动驾驶技术-应用场景城市公共交通优化”的大纲分析,可以从以下几个方面进行展开: 一、引言 简述智慧城市的概念及其重要性。强调智能交通在智慧城市中的核心地位。引出自动驾驶…...
[High Speed Serial ] Xilinx
Xilinx 高速串行数据接口 收发器产品涵盖了当今高速协议的方方面面。GTH 和 GTY 收发器提供要求苛刻的光互连所需的低抖动,并具有世界一流的自适应均衡功能,具有困难的背板操作所需的 PCS 功能。 Versal™ GTY (32.75Gb/s)&…...
Unity学习笔记(3):场景绘制和叠层设置 Tilemap
文章目录 前言开发环境规则瓦片绘制拐角 动态瓦片总结 前言 这里学一下后面的场景绘制和叠层技巧。 开发环境 Unity 6windows 11vs studio 2022Unity2022.2 最新教程《勇士传说》入门到进阶|4K:https://www.bilibili.com/video/BV1mL411o77x/?spm_id_from333.10…...
不吹不黑,客观理性深入讨论中国信创现状
1. 题记: 随着美国大选尘埃落定,特朗普当选美国新一任总统,参考他之前对中国政策的风格,个人预计他将进一步限制中国半导体产业和信创产业的发展。本篇博文不吹不黑,客观理性深入探讨中国信创现状。文中数据来自权威媒…...
NoSQL大数据存储技术测试(2)NoSQL数据库的基本原理
写在前面:未完成测试的同学,请先完成测试,此博文供大家复习使用,(我的答案)均为正确答案,大家可以放心复习 单项选择题 第1题 NoSQL的主要存储模式不包括 键值对存储模式 列存储模式 文件…...
「QT」几何数据类 之 QPoint 整型点类
✨博客主页何曾参静谧的博客📌文章专栏「QT」QT5程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…...
植物明星大乱斗5
能帮到你的话,就给个赞吧 😘 文章目录 timer.htimer.cppcamera.hcamera.cppmenuScene.cpp timer.h #pragma once #include <functional>class Timer {public:void reStart();void setTimer(int timerMs);void setIsOneShot(bool isOneShot);void …...
每日算法练习
各位小伙伴们大家好,今天给大家带来几道算法题。 题目一 算法分析 首先,我们应该知道什么是完全二叉树:若一颗二叉树深度为n,那么前n-1层是满二叉树,只有最后一层不确定。 给定我们一棵完全二叉树,我们查看…...
把握鸿蒙生态崛起机遇:开发者如何在全场景操作系统中脱颖而出
把握鸿蒙生态崛起机遇:开发者如何在全场景操作系统中脱颖而出 随着鸿蒙系统的逐步成熟和生态体系的扩展,其与安卓、iOS 形成了全新竞争格局,为智能手机、穿戴设备、车载系统和智能家居等领域带来了广阔的应用前景。作为开发者,如…...
字符串类型排序,通过枚举进行单个维度多个维度排序
字符串类型进行排序通过定义枚举值实现 1.首先创建一个测试类,并实现main方法 2.如果是单个维度的排序,则按照顺序定义一个枚举 public enum Risk {高风险,中风险,一般风险,低风险 } public static void main(String[] args) { }3.main方法里实现如下…...
figma的drop shadow x:0 y:4 blur:6 spread:0 如何写成css样式
figma的drop shadow x:0 y:4 blur:6 spread:0 如何写成css样式 在CSS中,我们可以使用box-shadow属性来模拟Figma中的Drop Shadow效果。box-shadow属性接受的值分别是:横向偏移、纵向偏移、模糊半径、扩展半径和颜色。 但是,Figma的Drop Sha…...
基于Matlab 疲劳驾驶检测
Matlab 疲劳驾驶检测 课题介绍 该课题为基于眼部和嘴部的疲劳驾驶检测。带有一个人机交互界面GUI,通过输入视频,分帧,定位眼睛和嘴巴,通过眼睛和嘴巴的张合度,来判别是否疲劳。 二、操作步骤 第一步:最…...
Linux内核.之 init文件,/init/main.c
想要熟悉内核,看下源码,就非常清晰 Linux内核,head.s,汇编启动cpu相关设置后,启动init文件里的,文件在内核的/init/main.c,看下main函数,做了哪些工作 // SPDX-License-Identifier: …...
CentOS系统中查看内网端口映射的多种方法
在网络管理中,了解和控制内网端口映射是至关重要的。本文将为您详细介绍在CentOS系统中查看内网端口映射的多种方法,助您提升网络管理效率。 使用netstat命令查看端口映射 netstat是一个强大的网络诊断工具。要查看当前的端口映射情况,可以在…...
Mac中禁用系统更新
Mac中禁用系统更新 文章目录 Mac中禁用系统更新1. 修改hosts,屏蔽系统更新检测联网1. 去除系统偏好设置--系统更新已有的小红点标记 1. 修改hosts,屏蔽系统更新检测联网 打开终端,执行命令: sudo vim /etc/hosts127.0.0.1 swdis…...
GoogLeNet-水果分类
GoogLeNet-水果分类 1.数据集 官方下载地址:https://www.kaggle.com/datasets/karimabdulnabi/fruit-classification10-class?resourcedownload 备用下载地址:https://www.123684.com/s/xhlWjv-pRAPh 介绍: 十个类别:苹果、…...
深度学习入门指南:一篇文章全解
目录 0.前言 1.深度学习的背景历史 2.深度学习主要研究的内容 3.深度学习的分支 3.1.卷积神经网络(CNN) 3.2 递归神经网络(RNN) 3. 3长短期记忆网络(LSTM) 4.深度学习的主要应用 4.1计算机视觉 4…...
java ssm 医院病房管理系统 医院管理 医疗病房信息管理 源码 jsp
一、项目简介 本项目是一套基于SSM的医院病房管理系统,主要针对计算机相关专业的和需要项目实战练习的Java学习者。 包含:项目源码、数据库脚本、软件工具等。 项目都经过严格调试,确保可以运行! 二、技术实现 后端技术&#x…...
钩子函数的使用
钩子函数在计算机科学和软件工程中,特别是在编程框架和库中,是一种特殊的函数或方法,它们允许用户在框架或库的特定点插入自定义代码。这些钩子提供了一种扩展框架功能而无需修改其源代码的方式。 在前后端分离的项目中,如使用Dj…...
【Docker】自定义网络:实现容器之间通过域名相互通讯
文章目录 一. 默认网络:docker0网络的问题二. 自定义网络三. nginx容器指之间通过主机名进行内部通讯四. redis集群容器(跳过宿主机)内部网络通讯1. 集群描述2. 基于bitnami镜像的环境变量快速构建redis集群 一. 默认网络:docker0…...
护理陪护系统|护理陪护软件|陪护软件
在当今社会,随着人口老龄化的加剧和生活节奏的加快,护理陪护服务的需求日益增长。为了满足这一需求,开发定制一套高效、专业的护理陪护系统显得尤为重要。在开发过程中,有几个关键方面不能忽视。 一、用户需求分析 护理陪护系统的…...
苍穹外卖-账号被锁定怎么办?
刚刚解决的小问题, 最近在搞黑马程序员的苍穹外卖项目, 在完善开发编辑员工功能的时候, 不知道怎么搞的, 无论是swagger接口测试, 还是前后端联调, 都显示"账号被锁定", 原本想在网上找找解释, 结果我太笨, 搜不到, 那就只能在代码里面排查咯, 既然是登录接口出…...
webpack loader全解析,从入门到精通(10)
webpack 的核心功能是分析出各种模块的依赖关系,然后形成资源列表,最终打包生成到指定的文件中。更多复杂的功能需要借助 webpack loaders 和 plugins 来完成。 1. 什么是 Loader Loader 本质上是一个函数,它的作用是将某个源码字符串转换成…...
python机器人Agent编程——实现一个本地大模型和爬虫结合的手机号归属地天气查询Agent
目录 一、前言二、准备工作三、Agent结构四、python模块实现4.1 实现手机号归属地查询工具4.2实现天气查询工具4.3定义创建Agent主体4.4创建聊天界面 五、小结PS.扩展阅读ps1.六自由度机器人相关文章资源ps2.四轴机器相关文章资源ps3.移动小车相关文章资源ps3.wifi小车控制相关…...
【动态规划】斐波那契数列模型总结
一、第 N 个泰波那契数 题目链接: 第 N 个泰波那契数 题目描述: 题目分析: 1、状态表示: dp[i] 表示:第 i 个斐波那契数的值 2、状态转移方程: 由题意可知第 i 个数等于其前三个数之和 dp[i] dp[i-…...
EasyUI弹出框行编辑,通过下拉框实现内容联动
EasyUI弹出框行编辑,通过下拉框实现内容联动 需求 实现用户支付方式配置,当弹出框加载出来的时候,显示用户现有的支付方式,datagrid的第一列为conbobox,下来选择之后实现后面的数据直接填充; 点击新增:新…...
国产linux系统(银河麒麟,统信uos)使用 PageOffice 实现word文件在线留痕
PageOffice 国产版 :支持信创系统,支持银河麒麟V10和统信UOS,支持X86(intel、兆芯、海光等)、ARM(飞腾、鲲鹏、麒麟等)、龙芯(LoogArch)芯片架构。 查看本示例演示效果 …...
使用亚马逊 S3 连接器为 PyTorch 和 MinIO 创建地图式数据集
在深入研究 Amazon 的 PyTorch S3 连接器之前,有必要介绍一下它要解决的问题。许多 AI 模型需要使用无法放入内存的数据进行训练。此外,许多为计算机视觉和生成式 AI 构建的真正有趣的模型使用的数据甚至无法容纳在单个服务器附带的磁盘驱动器上。解决存…...
自动化运维:提升效率与稳定性的关键技术实践
自动化运维:提升效率与稳定性的关键技术实践 在数字化转型的浪潮中,企业对于IT系统的依赖日益加深,系统的复杂性和规模也随之膨胀。面对这一挑战,传统的运维模式——依靠人工进行服务器的监控、配置变更、故障排查等任务…...
2016做砸了的小网站/苏州优化seo
认证概述HCIE-Cloud DataCenter Operations认证定位与云数据中心自动化运维、华为FusionCloud解决方案运维与运营、云数据中心整合迁移、容灾备份等技术的实操技能认证,旨在推动ICT行业云数据中心运维能人才的培养。HCIE-Cloud DataCenter Operations认证包括但不限…...
杭州做网站seo/seo排名推广工具
2019独角兽企业重金招聘Python工程师标准>>> 首先说下,我的是Sublime Text 3,win10。 ST有个插件View In Browser可以在浏览器里打开文件,但经过试用,报Encoding错误,其Github的issues里也有人提出了此bug&…...
建设网站公司不给源代码/地推拉新接单平台
0.前言 如果可以的话,请先关注(专栏和账号),然后点赞和收藏,最后学习和进步。你的支持是我继续写下去的最大动力,个人定当倾囊而送,不负所望。谢谢!!! 1.前提…...
自己做网站还是用别人网站/杭州seo价格
子查询 一、含义 嵌套在其他语句内部的select语句称为子查询或内查询, 外面的语句可以是insert、update、delete、select等,一般select作为外面语句较多 外面如果为select语句,则此语句称为外查询或主查询 二、分类 1、按出现位置 sele…...
达州达县网站建设/怎么才能在百度上做引流呢
一、数组的forEach中直接retrun fun main(args: Array<String>) {val arr intArrayOf(1,2,3,4,5,6,7)arr.forEach { if (it 4) returnprintln("value:$it") }println("this is End") }那么输出结果是 可以看到程序程序在遍历到4的时候就退出了方…...
东莞网站建设设计公司/搜索引擎排名2020
前言 pyquery库是jQuery的Python实现,能够以jQuery的语法来操作解析 HTML 文档,易用性和解析速度都很好,和它差不多的还有BeautifulSoup,都是用来解析的。相比BeautifulSoup完美翔实的文档,虽然PyQuery库的文档弱爆了…...