seo 新老网站替换 域名不变,黄金app软件下载大全免费,网站转换移动网站,设计网站广告语var、let、const之间有什么区别#xff1f;
var: 在ES5中#xff0c;顶层对象的属性和全局变量是等价的#xff0c;用var声明的变量既是全局变量#xff0c;也是顶层变量 注意#xff1a;顶层对象#xff0c;在浏览器环境指的是window对象#xff0c;在 Node 指的是g…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 declaredconst: 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 tagFuncmy 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)) //false5.参数默认值剩余参数 给函数形参设置默认值
// 带默认参数的形参一般放在后面减少传参导致的错误几率
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函数可以省略 keyvalue 形式可以直接 func(),可以使用计算属性比如{[Math.random()]: value}
/*** 1、增强了对象字面量* 1同名属性可以省略key:value形式直接key* 2函数可以省略keyvalue形式* 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)) //true11.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,}indexreturn 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,}indexreturn 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)) //-122.运算符-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 来完整复制对象包含 getset 方法
// 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来复制对象可以完整复制对象包含getset
const objGet2 Object.defineProperties({}, descriptors)
objGet2.bar 3
console.log(objGet2.getCount) //426.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); // undefined8、箭头函数不能用作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])
}