diff --git "a/\351\237\251\346\226\207\345\215\232/week15/ES.md" "b/\351\237\251\346\226\207\345\215\232/week15/ES.md" new file mode 100644 index 0000000..bf8cffb --- /dev/null +++ "b/\351\237\251\346\226\207\345\215\232/week15/ES.md" @@ -0,0 +1,407 @@ +ES全称EcmaScript,是脚本语言的规范,JS是ES的一种实现,所以ES的新特性可以应用到JS上 + +#### ECMA +European Computer Manufaturers Association,欧洲计算机制造商协会,评估、开发和认可电信和计算机标准。ES是通过ECMA-262标准的脚本程序设计语言。TC39(Technical Committee)负责推进ECMAScript发展,其会员公司包括苹果、谷歌、微软、因特尔等(浏览器厂商) + +## ES6 +#### let +用来声明可变变量,用let声明的变量不能重复,属于块级作用域。不存在变量提升,什么时候声明什么时候才能用。不影响作用域链 + +#### const +const用来声明常量,使用的时候必须赋初始值,一般常量整个要大写(比较通用),常量的值不会被修改,作用在块级作用域。对于常量数组和常量对象其中的元素的修改不算对整个常量的更改,所以不会报错,因为这个常量指向的数组或对象的地址没变;如果直接更改整个数据,那就会出错 + +#### 解构赋值 +```javascript +// 数组解构 +const arr = [123, 345, 456, 567] +let [num1, num2, num3, num4] = arr + +// 对象解构 +const obj = { + name: '张三', + age: 18, + getName: function() { + return this.name + } +} + +let {name, age, getName} = obj +``` + +#### 模板字符串 +用````声明字符串,内容中可以直接换行,可以进行变量拼接 + +#### 简化对象写法 +ES6允许在打括号里面直接写入变量和函数作为对象的属性和方法,这样的书写更加简洁 + +```javascript +let name = '张三' +let change = function(){ + console.log('更改') +} + +const school = { + name, + change +} + +// 等价于const school = { +// name: name, +// change: change +// } +``` + +在简化对象写法中,如果要写函数可以不加`=function`,如`const school = { improve(){...} }`,而不是`improve = function(){...}` + +#### 箭头函数 +可以省略function。箭头函数有一个非常重要的特性,其this是静态的,始终指向函数声明时所在作用域下的this的值,就算想要用call函数改变this也不会变。但是箭头函数不能作为构造函数实例化对象,也不能用arguments变量。如果只有一个参数可以省略参数的小括号,如果代码体只有一条语句时可以省略代码体的大括号;省略大括号时如果只是return语句,那么return也要省略。`let pow = n => n*n` + +我们可以在箭头函数外面保存要用到的this的值然后在函数中使用。主要就是简写,适合不与this有关的回调,如定时器、数组方法等;不适合事件回调,对象方法等(不是不能,有时候还是能用的) + +#### 函数参数默认值 +函数形参可以赋初始值,这样可以避免没传参数导致的错误;也可以与解构赋值结合来,比如没有传要解构的值,可以用默认值来获取解构后的值 + +#### rest +rest可以获取函数的实参,代替arguments。`function date(...args){...}`,这个args接收后是个数组,必须放在函数参数的最后,就是说剩下的参数等 + +#### 扩展运算符 +`...`就是扩展运算符,能将数组转换为逗号分隔的参数序列,就是可以用来展开获取到的参数。rest放在形参的位置,扩展运算符在调用时放在括号里。 + +扩展运算符可以用来合并数组,如`const arr = [...arr1, ...arr2]`;也可以用来克隆数组`const arr1 = [1, 2, 3]; const arr2 = [...arr1]`,也可以将伪数组转换为真正的数组,比如我们通过DOM操作获取对象内容后,可以用`...`展开对象内容并交给数组 + +#### symbol +原始数据类型,表示独一无二的值,其值唯一,用来解决命名冲突的问题,它不能与其他数据进行运算(如加减乘除,字符串拼接,比较等),symbol定义的对象属性不能用for in进行遍历,但是可以用`Reflect.ownKeys`来获取所有键名。就算两个symbol的内容相同,它们也不能算相等 + +可以使用Symbol.for来创建Symbol数据,只不过这是个函数对象,可以根据传入的字符串生成唯一的标识值,这样如果我们再通过Symbol.for传入相同的字符串,这两个Symbol会是相同的,如`let s1 = Symbol.for('123')`和`let s2 = Symbol.for('123')`,s1和s2是相等的 + +USONB可以简记基本数据类型: + ++ u:undefined ++ S:string symbol ++ O:object ++ n:null number ++ b:boolean + +Symbol可以用来向对象安全地添加方法和属性 + +```javascript +let game = {...} +let methods = { + up: Symbol(), + down: Symbol() +} + +game[methods.up] = function(){ + ... +} +game[methods.down] = function(){ + ... +} +// 这样不管game里面是否有up和down方法,都可以添加独一无二的Symbol方法,不会出错 +``` + +由于Symbol是动态的,是个表达式,在对象内部直接添加的时候需要前后加中括号`[Symbol('say')]:...` + +除了定义自己使用的Symbol以外,ES6还提供了11个内置的Symbol值,指向语言内部使用的方法,其实指的就是Symbol对象的属性,可以改变对象在特定情况下获得的结果 + +| Symbol.hasInstance | 当其他对象使用instanceof运算符判断是否为该对象的实例时,会调用这个方法 | +| ------------------------- | ------------------------------------------------------------------------------------------------------- | +| Symbol.isConcatSpreadable | 对象的Symbol.isConcatSpreadable实行等于一个布尔值,表示该对象用于Array.prototype.concat()时是否可以展开 | +| Symbol.unscopables | 该对象制定了使用with关键字时,哪些属性会被with环境排除 | +| Symbol.match | 当执行str.match(myObject)时,如果有该属性存在,会调用它,返回该方法的返回值 | +| Symbol.replace | 当该对象被str.replace(myObject)方法调用时,会返回该方法的返回值 | +| Symbol.search | 当该对象被str.search(myObject)方法调用时,会返回该方法的返回值 | +| Symbol.species | 创建衍生对象时,会使用该属性 | +| Symbol.split | 当该对象被str.split(myObject)方法调用时,会返回该方法的返回值 | +| Symbol.iterator | 对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器 | +| Symbol.toPrimitive | 该对象被转为原始类型的值时会调用这个方法,返回该对象对应的原始类型值 | +| Symbol.toStringTag | 在该对象上面调用toString方法时返回该方法的返回值 | +| Symbol.species | 创建衍生对象时会使用该属性 | + + +这些都是Symbol里面的属性,它们又作为一个整体当作对象的属性来设置,可以控制对象在特定情况下的表现,说白了就是扩展对象功能 + +#### 迭代器 +迭代器是一种接口,为各种不同的数据结构提供统一的访问机制。任何数据结构只要部署Iterator接口就可以完成遍历操作,Iterator就是对象里面的一个属性Symbol.iterator。ES6创造了一种新的遍历命令for...of循环,Iterator接口主要供for...of消费。原生具备Iterator接口的数据有:Array,Arguments,Set,Map,String,TypedArray,NodeList。for...in保存的是键名(如数组下标),for...of保存的是键值 + +Iterator会创建一个指针对象,指向当前数据结构的起始位置-第一次调用对象的next方法,指针自动指向数据结构的第一个成员-接下来不断调用next直到指针指向最后一个成员-在此期间每调用一次next方法都返回一个包含value和done属性的对象,done就是有没有遍历到最后 + +当我们想要自定义遍历数据的时候就要用到迭代器。forEach可以达到相同的效果,但是forEach是直接拿数据,不符合面向对象的思想;而Iterator可以设置在对象内部,属于的是对象本身,因此较为安全 + +```javascript +let index = 0 +let _this = this + +return { + next: function(){ + if(index < _this.stus.length) { + const result = { value: _this.stus[i], done: false } + index++ + return result + } else { + return { value: undefined, done: true } + } + } +} +``` + +#### 生成器 +生成器函数是ES6提供的一种异步编程解决方案,就是一个特殊的函数。原本异步编程都是纯回调函数一层套一层。生成器函数需要function和函数名之间有一个星号`function * gen(){}`,可以靠左可以靠右。其函数体由yield分割,可以理解为由从上往下的被yield分隔开的数组,然后要靠next来访问。next函数可以传入实参,其就是yield语句的返回结果 + +```javascript +function one(){ + setTimeout(()=>{ + console.log(111) + iterator.next() + }, 1000) +function two(){ + setTimeout(()=>{ + console.log(222) + iterator.next() + }, 2000) +function three(){ + setTimeout(()=>{ + console.log(333) + iterator.next() + }, 3000) +} + +function * gen(){ + yield one() + yield two() + yield three() +} + +let iterator = gen() +iterator.next() +``` + +#### Promise +是ES6引入的异步编程的新解决方案,从语法上来说Promise就是一个构造函数,用来封装异步操作并获取其成功或失败的结果。在Promise的回调函数内部写异步函数,在得到数据后可以调用回调函数的参数resolve和reject两个函数参数,它们分别会把Promise的状态设置为resolved和rejected,并执行它们所绑定的成功回调函数或失败回调函数。需要调用Promise对象的then方法来绑定resolve和reject相应的函数 + +then的返回对象也是一个Promise,其返回状态由回调函数的执行结果决定。如果回调函数中返回的结果是非Promise类型的属性,则返回值为成功对象的值;如果返回的是成功Promise对象,则返回值为resolve的值;如果返回的是失败Promise对象,则返回值为报错值;如果是抛出错误,则返回值为抛出的错误值 + +因为then返回的是Primise,我们可以对then方法再调用then来创造Promise链,在Promise链中写异步函数,这样就可以防止回调地狱 + +Promise对象由catch函数,传入reason原因函数参数,如果出错会直接跳过剩下的then直接到catch函数体 + +#### set +类似于数组,但是成员的值都是唯一的,支持iterator,可以使用扩展运算符和for...of等进行遍历。具有以下属性和方法 + ++ size:返回集合的元素个数 ++ add:添加一个新元素,返回当前集合 ++ delete:删除元素,返回boolean值 ++ has:检测集合中是否包含某个元素,返回boolean值 + +#### map +类似于对象,是键值对的集合,但是键不再只是字符串,各种类型的值(包括对象)都可以当作键。也支持iterator,可以使用扩展运算符和for...of进行遍历。有以下属性和方法: + ++ size:返回map的元素个数 ++ set:增加一个新元素,返回当前map ++ get:返回键名对象的键值 ++ has:检测map中是否包含某个元素,返回boolean值 ++ clear:清空集合,返回undefined + +#### class +ES6也提供了更传统语言的写法,引入了class类概念作为对象的模板。基板上ES6的class可以看作一个语法糖,它的绝大部分功能在ES5中都存在,而class写法只是让对象原型的写法更清晰,更面向对象 + +正常写法下实例对象是没有构造对象上的属性的,所以要在构造对象的protorype上加属性和方法才能让实例对象也能使用。直接在构造对象上写的函数就是它的静态成员,class语法糖下把属性或方法前面加static就表明它们是类的静态成员,不会被实例化 + +```javascript +function Phone(brand, price) { + this.brand = brand + this.price = price +} + +Phone.prototype.call = fucntion(){ + console.log("打电话") +} + +function SmartPhone(brand, price, color, size){ + // call改变this值 + Phone.call(this, brand, price) + this.color = color + this.size = size +} +// 设置子集构造函数的原型 +SmartPhone.prototype = new Phone +// 校正构造函数 +SmartPhone.prototype.constructor = smartPhone +// 设置子类的方法 +SmartPhone.prototype.photo = function(){ + console.log("拍照") +} +``` + +```javascript +class Phone { + constructor(brand, price) { + this.brand = brand + this.price = price + } + + call(){ + console.log("打电话") + } +} + +class SmartPhone extends Phone { + constructor(brand, price, color, size) { + // super就是父类的构造器方法 + super(brand, price) + this.color = color + this.size = size + } + + photo(){ + console.log("拍照") + } +} + +// 这样只要正常实例化就能用 +const xiaomi = new SmartPhone('xiaomi', '799', 'black', '4.7inch') +``` + +子类也可以对父类的方法进行重写,直接在子类中写重名的方法即可,但是子类是不能用调用父类的同名方法的,如用super调用。js中类不写构造函数是合法的 + +get函数可以在获取数据时调用,set函数会在设置数据时调用 + +```javascript +class Phone{ + get price(){ + console.log("价格被读取了") + return '$123' + } +// 可以在setter里面写判断,比如符合某种规定才能改变数据等 + set price(newVal) { + console.log("价格被修改了") + } +} +``` + +#### 数值扩展 ++ Number.EPSILON是JS表示的最小精度,其值接近2.2204460492503130808472633361816E-16。如果两个数的差值小于EPSILON就说明这两个数相等,主要用在浮点数运算上,比如最经典的问题0.1+0.2>0.3的情况,它们在运算上因为精度会出现问题,所以我们用差值小于EPSILON来认定相等 ++ 二进制0b开头(binary),八进制0o开头(octonary),十六进制0x开头(hexadecimal) ++ Number.isFinite检测一个数是否为有限数,无线数如100/0、Infinity等输出false ++ Number.isNaN检测数值是否为NaN ++ Number.parseInt和Number.parseFloat字符串转整数和浮点数,会省略数字后面的字符 ++ Number.isInteger判断一个数是否为整数 ++ Math.trunc将数字的小数部分抹掉(不是四舍五入) ++ Math.sign判断一个数是正数、负数还是0,分别返回1,-1,0 + +#### 对象方法扩展 ++ Object.is判断两个值是否完全相等,可以判断两个NaN是否相同(三等不能判断两个NaN是否相同) ++ Object.assign合并对象,传入两个参数,后面的参数会覆盖前面的参数,前面的参数是模板。用来合并配置比较合适 ++ Object.setPrototypeOf设置原型对象,Object.getPrototypeOf获取原型对象 + +#### 模块化 +模块化是指将一个大程序文件拆分成许多小文件,然后将小文件组合起来。可以防止命名冲突,小文件之间互不干扰;可以复用部分代码,也具有高维护性。ES6以前有一些模块化规范,如CommonJS(NodeJS,Browserify),AMD(requireJS),CMD(seaJS)等 + +模块功能主要由两个命令构成:export和import。分别用来规定模块的对外接口和输入其他模块提供的功能。我们需要在想要暴露出来的数据或方法前面加export,如`export let data = '123'`;在使用有import的文件时,要给script加`type="module"`属性 ,在文件内或script标签内`import * as file1 from './js/file1.js'`,这样js就把文件中所有export出的数据存到变量file1里面了 + +分别给属性和方法添加export修饰叫分别暴露,如果在文件添加`export {school, work}`,就会统一暴露文件中的school和work属性。引入是相同的方式。可以在文件内添加`export default{}`默认暴露数据,内部可以写数据,一般写成对象形式,在使用的时候需要`file.default.function()`,要访问default + +导入支持解构赋值,如文件内有school和teach属性,就可以`import {school, teach} from ...`。默认暴露的输出结果是个对象,在default里面存的是数据,所以我们需要进行别名设置,不能直接使用default,使用别名才可以 + +模块导入还有一种简便的形式,只能用在默认暴露上,直接`import file from "./js/file.js"`,拿到的就是默认暴露出来的对象 + +如果写成分开的js文件,就应该加`type="module"`属性和src属性 + +项目中一般不是直接script导入js文件,可以用Babel将ES6转化成ES5再打包形成单独文件,然后页面引入即可。npm安装babel-cli(babel命令行工具)、babel-preset-env(预设包,可将ES特性转换成ES5语法)、browserify(打包工具,实际项目一般使用webpack) + +在ES6下使用npm安装的包,可以用import导入安装过的要使用的包 + +## ES7 +引入了Array.prototype.includes方法来检测数组中是否包含某个元素并返回布尔类型值 + +指数运算符`**`,功能与Math.pow结果相同 + +## ES8 +#### async和await +async和await结合可以简化异步代码,让它像同步代码一样。async函数的返回值为promise对象,其结果由async函数执行的返回值决定。await必须卸载async函数中,其右侧表达式一般为promise对象,若promise成功则返回promise成功的值,否则会抛出异常,需要try...catch处理。我们只需要在需要用到的异步函数内将数据绑定给Promise,然后再给await使用这个异步函数就可以大大简化异步处理的过程 + +#### 对象方法扩展 ++ Object.values()方法返回一个给定对象的所有可枚举属性值的数组 ++ Object.entries()方法返回一个给定对象自身可遍历属性[key, value]的数组,方便我们创建map ++ Object.getOwnPropertyDescriptors()方法返回对象所有自身属性的描述对象,如writable、configurable、enumerable等 + +## ES9 +#### 对象展开 +Rest参数与spread扩展运算符在ES6就已经引入,但是仅针对数组。ES9开始为对象提供像数组一样的rest参数和扩展运算符。可以用于对象的合并等 + +#### 正则扩展 ++ 命名捕获分组 + +对分组匹配的结果进行命名,方便对数据进行处理 + +```javascript +let str = 'B站' +// 正则匹配的时候在前面加上?<命名> +const reg = /(?.*)<\/a>/ +``` + ++ 反向断言 + +可以根据前面的内容匹配后面的内容 + +```javascript +// 正向断言,从后面的内容匹配前面的内容 +let str = "1235451一二三810四四四" +// /d表示数字,+表示匹配多次(多个) +const reg1 = /\d+(?=四)/ +// 反向断言 +const reg2 = /(?<=三)\d+/ +``` + ++ dotAll模式 + +`.`是元字符,表示除换行符以外的任意单个字符 + +## ES10 ++ Object.fromEntries()用来创建一个对象,接收二维数组或map;在ES8中的Object.entries可以转化为数组 + +#### 字符串扩展 ++ trimStart:trim用来清除字符串两端的空白字符,trimStart可以指定清除字符串左端的空白字符 ++ trimEnd:指定清除字符串右端的空白字符 + +#### 数组扩展 ++ flat:将多维数组转化为低维数组,可以接受数字参数表示深度,如传入1则只展开一层,到2维;传入2展开到3维。默认参数1 ++ flatMap:将map维度降低 + +#### Symbol扩展 ++ Symbol.prototype.description:用来获取Symbol的字符串描述 + +## ES11 ++ 可选链操作符:`?.`,当我们应对对象类型的参数时,其深度较深 + +```javascript +main({ + db: { + host:'192.168.1.100' + username: 'root' + }, +cache: { + host: '192.168.101' + username: 'admin' + } +}) + +// 可以用可选链操作符判断某层是否有某属性,否则需要挨个判断 +const dbHost = config?.db?.host +``` + ++ 动态import:静态import就是在前面直接引入文件,动态import我们可以在代码内部使用import函数,它返回一个Promise对象,其成功值就是文件export出的属性和方法 ++ globalThis:不管怎么样它指向的都是全局对象(浏览器下是Window对象) + +#### 私有属性 +在面向对象是个非常重要的属性,对属性进行封装,不能被其他文件进行直接访问。公有属性直接写属性即可,私有属性要在前面加井号如`#age`、`#weight`等,在类内部访问私有属性的时候也要写全,如`this.#age = age` + +#### Promise扩展 ++ Promise.allSettled:接收一个Promise数组,返回一个Promise对象,其结果永远都是成功,成功的值是每个Promise的状态和结果 + +#### 字符串扩展 ++ String.prototype.matchAll:用来得到正则批量匹配的结果,爬虫类很有效 + +#### 类型扩展 ++ BigInt:大整形转换,不能用浮点数进行转换和与正常数值运算,可以用于大数值运算 + diff --git "a/\351\237\251\346\226\207\345\215\232/week15/\345\221\250\346\212\245.md" "b/\351\237\251\346\226\207\345\215\232/week15/\345\221\250\346\212\245.md" new file mode 100644 index 0000000..8167e51 --- /dev/null +++ "b/\351\237\251\346\226\207\345\215\232/week15/\345\221\250\346\212\245.md" @@ -0,0 +1,18 @@ +## 0915 周报 +### 学习笔记/记录 +- 这周学完了ES剩下的部分,继续学node +- 继续研究LogicFlow,感觉还挺有意思的 + +#### 要注意的知识点 +- rest可以获取函数的实参,args放在函数中参数的最后,获取剩下的参数 +- 扩展运算符可以用来合并数组 +- symbol.for可以根据字符串数据生成唯一的标识值。symbol可以用来向对象安全地添加方法和属性 +- for...in保存的是键名,for...of保存的是键值 +- forEach和iterator都能达到遍历的效果,但是forEach是直接获取数据,不符合面向对象的思想 +- Number.EPSILON表示JS的最小精度,像0.1+0.2>0.3这种情况就能用两边差值小于Number.EPSILON来表示相等 +- 命名捕获数组?.* +- flat和flatMap将多维转为低维 +- 可选链操作符?.,可以判断某层是否有某属性如config?.db?.host +- 动态import函数返回Promise对象,其成功值是文件export的属性和方法 +- 私有属性#name等就算是在类内部访问也要写全,如this.#age = age +- BigInt不能用浮点数进行转换,也不能与正常数值运算 \ No newline at end of file