为什么网站目录不收录seowhy问答

news/2025/9/27 10:41:08/文章来源:
为什么网站目录不收录,seowhy问答,vue 网站做中英文切换,wordpress 菜单跳转一、初识 1.1 基础 1.1.1 语言速成课 1.1.1.1 变量 ​ 变量是存储值的容器。首先用let关键字声明一个变量#xff0c;后面跟着你给变量的名字 ​ 变量命名区分大小写 ​ 分号在JavaScript中是用来分隔语句的#xff0c;但是如果语句后面有一个换行符(或者在{block}中只…一、初识 1.1 基础 1.1.1 语言速成课 1.1.1.1 变量 ​ 变量是存储值的容器。首先用let关键字声明一个变量后面跟着你给变量的名字 ​ 变量命名区分大小写 ​ 分号在JavaScript中是用来分隔语句的但是如果语句后面有一个换行符(或者在{block}中只有一个语句)分号可以省略。 1.1.1.2 注释 ​ 多行注释/*comments*/ ​ 单行注释/comments/ 1.1.1.3 运算符 ​ 运算符是一种基于两个值(或变量)产生结果的数学符号 1.1.1.4 条件语句 ​ 条件是用于测试表达式是否返回真值的代码结构 1.1.1.5 函数 ​ 函数是对希望重用的功能进行打包的一种方式 1.1.1.6 事件 ​ 网站上真正的交互性需要事件处理程序。这些代码结构监听浏览器中的活动并在响应中运行代码 1.2 第一步 1.2.1 什么是javaScript JavaScript是一种脚本或编程语言它允许你在网页上实现复杂的功能 JavaScript是一种轻量级的解释性编程语言 1.2.2 第一次使用js 1.2.3 故障排除 1.2.4 变量 1.2.4.1 变量声明 声明变量let myName; 在JavaScript中所有代码指令都应该以分号(;)结束——你的代码可能在单行中正常工作但当你一起编写多行代码时可能就不行了 不要混淆存在但没有定义值的变量和根本不存在的变量。不存在意味着没有盒子没有定义值意味着有一个盒子但是里面没有值 1.2.4.2 初始化变量 初始化变量myName Chris; 也可以声明和初始化同时进行let myDog Rover; 1.2.4.3 关于var的说明 var会变量提升let不会提升 myVar 9; console.log(myVar); var myVar;//使用var正常工作 let myVar;//使用let报错推荐方式var可以重复声明let不会 var myVar;//可以重复声明 var myVar;//使用var正常工作let myVar;//不可重复声明 let myVar;//使用let报错推荐方式1.2.4.4 常量 常量声明时必须初始化 初始化后不能赋新值 虽然常量不能更改但是如果常量类型是对象的话对象的内容是可以更改的。 使用const还是let声明变量时对其进行初始化并且以后不需要对其重新赋值则将其设置为常量 1.2.5 数值和操作符 **操作符为指数操作符 JavaScript中的运算符优先级和学校数学课上教的一样——乘和除总是先做然后是加和减(计算总是从左到右计算)。 和!测试值是否相同但不测试值的数据类型是否相同。和!是严格版本测试值及其数据类型是否相等。严格的版本往往会导致更少的错误因此我们建议您使用它们 1.2.6 字符串 在JavaScript中您可以选择单引号(‘)、双引号()或反引号(’)来包装字符串 使用反引号声明的字符串是一种特殊类型的字符串称为模板字面量。在大多数情况下模板字面值就像普通的字符串但是它们有一些特殊的属性: 你可以在其中嵌入JavaScript可以在多行上声明模板字面量 在模板字面量中你可以将JavaScript变量或表达式包装在${}中结果将包含在字符串中 const name Chris; const greeting Hello, ${name}; console.log(greeting); // Hello, Chris${}只能用于模板字面量不能用于普通字符串。您可以使用操作符连接普通字符串 你可以在模板字面量中包含JavaScript表达式也可以只是变量结果将包含在结果中 const output I like the song ${song}. I gave it a score of ${(score / highestScore) * 100}%.;模板字面量尊重源代码中的换行符所以你可以像这样编写跨多行的字符串 const newline One day you finally knew what you had to do, and began,;1.2.7 有用的字符串方法 1.2.8数组 数组itmes执行相同操作使用map() function double(number) {return number * 2; } const numbers [5, 2, 7, 6]; const doubled numbers.map(double); console.log(doubled); // [ 10, 4, 14, 12 ] 数组itmes过滤使用filter() function isLong(city) {return city.length 8; } const cities [London, Liverpool, Totnes, Edinburgh]; const longer cities.filter(isLong); console.log(longer); // [ Liverpool, Edinburgh ] 1.3 构建块 1.3.1 条件 1.3.2 循环 1.3.3 函数 与函数声明不同函数表达式不会被提升。 1.3.4 自定义函数 1.3.5 函数返回值 1.3.6 事件介绍 1.3.6.1 阻止事件默认行为 e.preventDefault();1.3.6.2 阻止事件冒泡 event.stopPropagation();currentTarget 和 target 是 JavaScript 事件对象的两个属性它们的区别在于它们分别引用的元素。 event.target这个属性返回的是触发事件的元素也就是真正的事件源头。例如如果你在一个按钮上点击那么 event.target 就会返回那个按钮元素。event.currentTarget这个属性返回的是事件侦听器绑定的元素。例如如果你在一个 div 元素上绑定了点击事件然后在这个 div 的一个按钮上点击那么 event.target 会返回按钮元素但是 event.currentTarget 会返回 div 元素。 在大多数情况下event.target 和 event.currentTarget 指向的是同一个元素但是在事件冒泡或者事件捕获的情况下它们可能会指向不同的元素。例如如果你在父元素上绑定了一个事件监听器然后在它的一个子元素上触发了那个事件这个时候 event.target 就会返回子元素而 event.currentTarget 会返回父元素。 开启捕获addEventListener的第三个参数{ capture: true }。捕获和冒泡的顺序相反 为什么要同时捕获和冒泡呢?在糟糕的过去浏览器的交叉兼容性远不如现在Netscape只使用事件捕获Internet Explorer只使用事件冒泡。当W3C决定尝试标准化行为并达成共识时他们最终采用了包含这两者的系统 1.3.6.3 事件委托 将子元素的单击事件委托给父元素。 父元素绑定事件使用事件对象的target属性来获得单击的目标子元素 1.3.7 图片库 1.4 对象介绍 1.4.1 对象基础 对象字面量 const person {name: [Bob, Smith],age: 32,bio() {//bio: function ()简写console.log(${this.name[0]} ${this.name[1]} is ${this.age} years old.);}, };对象访问点表示法通常比括号表示法更受欢迎因为它更简洁更容易阅读。然而在某些情况下你必须使用方括号。例如如果对象属性名称保存在变量中则不能使用点表示法访问该值但可以使用括号表示法访问该值。 例如 const person {name: [Bob, Smith],age: 32, };function logProperty(propertyName) {console.log(person[propertyName]);//此处不能使用点 }logProperty(name); // [Bob, Smith] logProperty(age); // 32 1.4.2 对象原型 1.4.2.1 介绍 javaScript中的每个对象都有一个内置属性称为原型。原型本身就是一个对象所以原型会有自己的原型形成所谓的原型链。当我们到达一个自己的原型为null的原型时这个链条就结束了 原型的原型一般不叫prototype它的名字不标准但实际上所有浏览器都使用__proto__,访问对象原型的标准方法是Object . getPrototypeof(对象)方法。 当你试图访问对象的属性时:如果在对象本身中找不到该属性则在原型中搜索该属性。如果仍然找不到属性则搜索原型的原型以此类推直到找到属性或到达链的末端在这种情况下返回undefined。 Object.prototype原型是Object的原型他的值是null它是所有原型的末端 1.4.2.2 设置原型的方法 设置原型的方法这里我们将介绍两种:object .create()和构造函数。 // const personPrototype {greet() {console.log(hello!);}, };const carl Object.create(personPrototype);//使用object.create()创建一个以personPrototype为原型的新对象 carl.greet(); // hello!构造函数 const personPrototype {greet() {console.log(hello, my name is ${this.name}!);}, };function Person(name) {this.name name; }Object.assign(Person.prototype, personPrototype); // or // Person.prototype.greet personPrototype.greet;你可以使用静态object . hasown(对象属性名)方法检查一个属性是否为自己的属性 1.4.3 面向对象编程 多态子类实现父类的方法就叫多态 封装对象的属性只能被自己的方法访问对外只暴露公共接口 1.4.4 类 1.4.4.1 类和构造函数 这里描述的功能并不是一种组合对象的新方式:在底层它们仍然使用原型。它们只是一种使建立原型链更容易的方法。 class Person {name;constructor(name) {//如果你不需要做任何特殊的初始化你可以省略构造函数它会为你生成一个默认构造函数this.name name;}introduceSelf() {console.log(Hi! Im ${this.name});} }const giles new Person(Giles);1.4.4.2 继承 class Professor extends Person {teaches;constructor(name, teaches) {super(name);//使用super()调用父类构造函数this.teaches teaches;}introduceSelf() {console.log(My name is ${this.name}, and I will be your ${this.teaches} professor.,);}grade(paper) {const grade Math.floor(Math.random() * (5 - 1) 1);console.log(grade);} } 1.4.4.3 封装 私有数据属性必须在类声明中声明其名称以#开头。 私有方法它们的名称以#开头并且只能由对象自己的方法调用: 1.4.5 使用JSON parse():接受JSON字符串作为参数并返回相应的JavaScript对象stringify():接受一个对象作为参数并返回等效的JSON字符串。 1.4.6 对象构建练习 requestAnimationFrame()函数 该方法需要传入一个回调函数作为参数该回调函数会在浏览器下一次重绘之前执行。回调函数执行次数通常是每秒 60 次. 若你想在浏览器下次重绘之前继续更新下一帧动画那么回调函数自身必须再次调用 requestAnimationFrame()。requestAnimationFrame() 是一次性的。 function loop() {requestAnimationFrame(loop);console.log(执行循环); } loop();1.4.7 添加功能到我们的弹跳球演示 二、指南 2.1 语法和类型 2.1.1 基础 如果语句单独写在一行中则不需要在语句后面加上分号。但是如果一行中需要多个语句则它们必须用分号分隔 2.1.2 注释 注释不能嵌套 /*这是/*dfdf*/注释*//*这是/*dfdf*\/注释*/2.1.3 声明 2.1.3.1 变量声明 var声明一个变量可选地将其初始化为一个值。let声明一个块作用域的局部变量可选地将其初始化为一个值。const声明一个块作用域的只读命名常量。 const { bar } foo这将创建一个名为bar的变量并将对应于对象foo中同名键的值赋给它 变量应该在使用之前声明。JavaScript过去允许对未声明的变量赋值这会创建一个未声明的全局变量。这是严格模式下的错误应该完全避免。 如果在没有初始化式的情况下声明变量则为其赋值undefined const声明总是需要一个初始化值因为它们禁止在声明之后进行任何类型的赋值 2.1.3.2 变量作用域 全局作用域在脚本模式下运行的所有代码的默认作用域模块作用域以模块模式运行的代码的作用域函数作用域用函数创建的作用域。块作用域用一对花括号(一个块)创建的作用域。使用let或const声明的变量 用var创建的变量不是块作用域而只是块所在函数的局部作用域(或全局作用域)。 2.1.3.3 变量的提升 var声明的变量是提升的这意味着您可以在其作用域中的任何地方引用该变量即使尚未到达其声明。 var声明被“提升”到它的函数或全局作用域的顶部 //注意是声明被提升而赋值没有被提升 console.log(x undefined); // true var x 3; //等价于 var x; console.log(x undefined); // true x 3;2.1.3.4 全局变量 全局变量实际上是全局对象window的属性 在不同的JavaScript运行环境中全局对象被命名为不同的名称。在浏览器环境中是window在Node.js环境中是global在Web Worker中是self。然而这种情况在JavaScript中引入globalThis后得到了统一无论在哪种环境下globalThis都被定义为全局对象。 2.1.3.5 常量 对象常量的属性是可以更改的 数组常量的数组元素可以更改的 2.1.4 数据结构和类型 2.1.4.1 数据类型 七种基本数据类型 Booleantrue和falsenull表示空值的特殊关键字undefined值没有被定义的顶级属性Number整型或浮点数值BigInt任意精度的整型String字符序列表示文本值Symbol实例是唯一的且不可变的 一种非基本类型 Object console.log(typeof null); // object这被认为是一个错误但是一个无法修复的错误因为它会破坏太多的脚本 2.1.4.2 数据类型转换 JavaScript是一种动态类型语言。这意味着在声明变量时不必指定它的数据类型。这还意味着在脚本执行期间数据类型会根据需要自动转换 //不会导致错误 let answer 42; answer Thanks for all the fish!;2.1.4.3 数值和‘’操作符 z 37 7; // 377 37 - 7; // 30 37 * 7; // 2592.1.4.4 转换字符串为数值 console.log(parseInt(123));// 123 (默认基本进制是10) console.log(parseInt(123, 10));// 123 (明确指定进制) console.log(parseInt( 123 ));// 123 (空格被忽略) console.log(parseInt(077));// 77 (前置0被忽略) console.log(parseInt(1.9));// 1 (小数后被忽略) console.log(parseInt(ff, 16));// 255 (小写16进制) console.log(parseInt(0xFF, 16));// 255 (前缀位0x的大写16进制) console.log(parseInt(xyz));// NaN (输入不能转换为整数)console.log(parseFloat(1.23));// 1.23 console.log(parseFloat(1.23aaa));// 1.23(1.1) (1.1); // 2.22.1.5 字面量 2.1.5.1 数组字面量 const coffees [French Roast, Colombian, Kona];//当使用Array.prototype.map等数组遍历方法时。映射时空槽被跳过。但是访问索引的fish[1]仍然返回undefined const fish [Lion, , Angel];//[Lion, empty, Angel]const myList [home, , school];//length3 const myList [, home, , school];//length4 const myList [home, , school, ,];//length4,最后逗号忽略//但是在编写自己的代码时应该显式地将缺失的元素声明为未定义或者至少插入注释以突出其缺失。这样做可以提高代码的清晰度和可维护性 const myList [home, /* empty */, school, /* empty */, ];2.1.5.2 布尔字面量 //布尔类型有两个字面量值:true和false2.1.5.3 数值字面量 0, 117, 123456789123456789n //十进制 015, 0001, 0o777777777777n //八进制 0x1123, 0x00111, 0x123456789ABCDEFn //十六进制 0b11, 0b0011, 0b11101001010101010101n //二进制 //整数字面值后面的n后缀表示BigInt字面值//浮点字面量[digits].[digits][(E|e)[(|-)]digits] 3.1415926 .123456789 3.1E12 .1e-232.1.5.4 对象字面量 const car { myCar: 字符串, getCar: 函数, special: 变量 };//对象属性名可以是任意字符串包括空字符串。如何属性名不是合法的js修饰符和数字它必须被加引号。并且调用时只能使用方括号 const unusualPropertyNames {: An empty string,!: Bang! } console.log(unusualPropertyNames.); // SyntaxError: Unexpected string console.log(unusualPropertyNames.!); // SyntaxError: Unexpected token ! console.log(unusualPropertyNames[]); // An empty string console.log(unusualPropertyNames[!]); // Bang!//增强对象字面量 const obj {// __proto__设置原型__proto__: theProtoObj,// 简写handler: handlerhandler,// 方法toString() {// 调用父级return d super.toString();},// 计算 (动态) 属性名[prop_ (() 42)()]: 42, }; 2.1.5.5 正则表达式字面量 //是用斜杠括起来的模板 const re /abc/;2.1.5.6 字符串字面量 除非特别需要使用string对象否则应该使用字符串字面值 //字符串字面值是用双引号()或单引号()括起来的零个或多个字符 foo bar//模板字符串 In JavaScript \n is a line-feed. const name Lev, time today; Hello ${name}, how are you ${time}?//插值语法 var s say console.log(你是说${s})//你是说say console.log(你是说%o,s)//你是说say//字符串多行显示使用反斜杠写在行末尾2.2 控制流和错误处理 2.2.1 块语句 最基本的语句是块语句用于对语句进行分组。该块由一对花括号分隔 {statement1;statement2;// …statementN; }块语句通常与控制流语句(if, for, while)一起使用。 { x; }是块语句 注意var声明的变量不是块作用域而是包含函数或脚本的作用域设置它们的效果在块本身之外持续存在。 2.2.2 条件语句 JavaScript支持两个条件语句:if…Else和switch 2.2.2.1 if语句 如下值被认定为false falseundefinednull0NaN空字符串 const b new Boolean(false); if (b) {// b是对象所以一直为true } if (b true) {// b的值是否等于true不等于 }2.2.2.2 switch语句 switch语句允许程序对表达式求值并尝试将表达式的值与case标号匹配。如果找到匹配项则程序执行相关语句 2.2.3 异常处理语句 你可以使用throw语句抛出异常并使用try…catch语句处理异常 2.2.3.1 异常类型 ECMAScript exceptionsDOMException 2.2.3.2 throw语句 throw Error2; // String type throw 42; // Number type throw true; // Boolean type throw {toString() {return Im an object!;}, };2.2.3.3 try…catch 语句 try {throw new Error(my) } catch (error) {console.error(error) }finally{console.log(始终需要执行的代码) }finally块中若有返回值这个值将是整个try…catch…finally放在函数里的返回值不管try和catch中是否有返回值该返回值也会覆盖catch中抛出的异常 function f() {try {throw bogus;} catch (e) {return true;} finally {return false; // 函数返回false} }2.2.3.4 利用错误对象 根据错误的类型您可以使用name和message属性来获得更精细的消息。 message通常提供比将错误对象转换为字符串得到的消息更简洁的消息 2.3 循环和迭代 循环中单个语句可以部使用大括号。多个语句必须使用大括号 2.3.1 for 语句 for (initialization; condition; afterthought)statement 2.3.2 do…while 语句 //先做某一件事然后再判断 dostatement while (condition);2.3.3 while 语句 //先判断条件满足再做某事 while (condition)statement2.3.4 labeled 语句 提供了一个带有标识符的语句使您可以在程序的其他地方引用它 使用break和continue时用于指定跳出的循环是哪个 label:statement 2.3.5 break 语句 当您使用不带标签的break时它会立即终止最内层的while、do-while、for或switch语句并将控制转移到下面的语句 当您使用带有标签的break时它将终止指定的带标签语句。 break跳出整个循环 break; break label;2.3.6 continue 语句 跳出本次循环 continue; continue label;2.3.7 for…in 语句 迭代属性名包括自定义属性 for (variable in object)statement语句除了返回数值索引外还将返回用户定义属性的名称因此用传统for循环迭代数组更合适 2.3.8 for…of 语句 迭代属性值不包括自定义属性 for (variable of object)statement//for...in和for...of的对比 const arr [山河,百川,溪流] arr.name 傻子console.log(arr)for (const at in arr) {console.log(at)//0 1 2 name}for (const at of arr) {console.log(at)//山河 百川 溪流 } 解构 const obj { foo: 1, bar: 2 };for (const [key, val] of Object.entries(obj)) {console.log(key, val); } // foo 1 // bar 22.4 函数 2.4.1 定义函数 2.4.1.1 函数声明 function square(number) {return number * number; } 函数参数传递一个值时在函数内部对值进行更改时对函数外部不会影响 函数参数传递一个对象时在函数内部修改对象时在函数外部对象会受影响 函数参数传递一个数组时在函数内部修改数组时在函数外部数组会受影响 2.4.1.2 函数表达式 将函数作为参数传递时会方便很多 //它是匿名的也可以有名字 const square function (number) {return number * number; };console.log(square(4)); // 16可以根据条件创建函数将函数写在if语句中 还可以使用Function构造函数由字符串创建函数 2.4.2 调用函数 函数被调用时必须在作用域中但是函数声明可以被提升(出现在代码中调用的下面) 函数提升只适用于函数声明而不适用于函数表达式 事实证明函数本身就是对象——反过来这些对象也有方法。call()和apply()方法可用于实现此目标。 2.4.3 函数作用域 在函数内部定义的变量不能从函数外部的任何地方访问因为变量只在函数的作用域中定义。但是函数可以访问它自己所在作用域中的变量和函数 在全局作用域中定义的函数可以访问全局作用域中定义的所有变量。在另一个函数中定义的函数也可以访问其父函数中定义的所有变量 2.4.4 作用域与函数堆栈 2.4.4.1 递归 函数有三种方式调用自己 函数名arguments.callee引用函数的作用域内变量 const foo function bar() {//如下三种方式都可以调用自身是等价的。bar();arguments.callee();foo(); }; 2.4.4.2 嵌套函数和闭包 一个函数可以嵌套在另一个函数中内部函数对于它的外部函数是私有的。 内部函数只能在外部函数的作用域中访问 内部函数形成一个闭包内部函数可以使用外部函数的参数和变量外部函数不能使用内部函数的参数和变量 function outside(x) {function inside(y) {return x y;}return inside; }const fnInside outside(3); // console.log(fnInside(5)); // 8 console.log(outside(3)(5)); // 82.4.4.3 变量的保存 当inside返回时x是如何保存的 闭包必须保留它引用的所有作用域中的参数和变量因为每一次调用传递不同的参数每次调用outside新的闭包会被创建直到返回的inside不再可访问内存才被释放 2.4.4.4 多嵌套函数 因此闭包可以包含多个作用域;它们递归地包含包含它的函数的作用域。这被称为作用域链 2.4.4.5 命名冲突 function outside() {const x 5;function inside(x) {return x * 2;}return inside; }console.log(outside()(10)); // 20 (instead of 10)2.4.5 闭包 js允许函数嵌套内部函数可以访问外部函数中定义的所有变量和函数以及外部函数可以访问的所有其他变量和函数 但是外部函数不能访问内部函数中定义的变量和函数。这为内部函数的变量提供了一种封装 因此如果内部函数设法在外部函数的生命周期之外存活return 内部函数那么在外部函数中定义的变量和函数将比外部函数执行的持续时间更长。当内部函数以某种方式可用于外部函数之外的任何作用域时就创建了闭包 2.4.6 使用arguments对象 函数的参数保存在一个类似数组的对象中arguments例如第一个参数arguments[0]等等 如果您事先不知道将向函数传递多少参数这通常是有用的 注意arguments变量是“类数组”但不是数组。它类似于数组因为它具有编号索引和长度属性。但是它不具备所有的数组操作方法。 2.4.7 函数参数 2.4.7.1 默认参数 在JavaScript中函数的参数默认为undefined function multiply(a, b 1) {return a * b;//b如果不传递值默认为1 }2.4.7.2 剩余参数 function test(...args){console.log(arguments)console.log(args) } test(1,4,3,5)2.4.8 箭头函数 箭头函数并且没有自己的this、arguments、super或new.target。箭头函数总是匿名的 箭头函数this指向的问题 function Person() {this.age 0; //此this指向Person的实例setInterval(function growUp() {this.age; //此this指向window}, 1000); }//解决this指向问题 function Person() {const self this;self.age 0;setInterval(function growUp() {self.age;}, 1000); }//使用箭头函数解决this指向问题 function Person() {this.age 0; // 此this指向Person的实例setInterval(() {this.age; // 此this指向Person的实例}, 1000); }const p new Person();2.5 表达式和操作符 2.5.1 赋值运算符 赋值操作符根据右操作数的值将值赋给左操作数 2.5.1.1 属性赋值 const obj {};obj.x 3; console.log(obj.x); // Prints 3. console.log(obj); // Prints { x: 3 }.const key y; obj[key] 5; console.log(obj[key]); // Prints 5. console.log(obj); // Prints { x: 3, y: 5 }.//在严格模式下下面的代码抛出异常因为不能给基本类型变量分配属性。 const val 0; val.x 3;console.log(val.x); // Prints undefined. console.log(val); // Prints 0.2.5.1.2 解构 通过解构你可以使用一条语句将多个值提取到不同的变量中: const foo [one, two, three]; const [one, two, three] foo;2.5.1.3 链式赋值语句 尽量避免使用链式赋值语句 //如下实际只声明了变量z const z y x f();2.5.2 比较运算符 在大多数情况下如果两个操作数不是同一类型JavaScript会尝试将它们转换为合适的类型进行比较 这种行为通常会导致操作数的数值比较。比较中类型转换的唯一例外涉及和!操作符它们执行严格的相等和不相等比较。在检查相等性之前这些操作符不会尝试将操作数转换为兼容类型 2.5.3 算术运算符 算术运算符将数值(字面量或变量)作为其操作数并返回单个数值 2.5.4 按位运算符 位运算符将其操作数视为32位(0和1)的集合而不是十进制、十六进制或八进制数 2.5.5 逻辑运算符 逻辑运算符通常用于布尔(逻辑)值;如果是则返回一个布尔值。 然而和||操作符实际上返回的是指定操作数之一的值因此如果这些操作符与非布尔值一起使用它们可能返回非布尔值 //逻辑与第一个为true则返回第二个值第一个为false直接返回第一个值 const a5 Cat Dog; // t t returns Dog const a6 false Cat; // f t returns false const a7 Cat false; // t f returns false//逻辑或第一个为true则返回第一个值第一个为false直接返回第二个值 const o5 Cat || Dog; // t || t returns Cat const o6 false || Cat; // f || t returns Cat const o7 Cat || false; // t || f returns Cat2.5.6 长整型数字运算符 在表示大整数时bigint比number具有更高的精度但不能表示小数 bigint和数字不能相互替换——你不能在计算中混合使用它们 你可以比较bigint和数字。a 1n 2; 2.5.7 字符串运算符 除了可用于字符串值的比较操作符之外连接操作符()还将两个字符串值连接在一起返回另一个字符串该字符串是两个操作数字符串的并集。 2.5.8 三元运算符 条件操作符是唯一接受三个操作数的JavaScript操作符。根据条件运算符可以有两个值之一 condition ? val1 : val22.5.9 逗号运算符 逗号操作符()计算它的两个操作数并返回最后一个操作数的值。这个操作符主要在for循环中使用允许在每次循环中更新多个变量 const x [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; const a [x, x, x, x, x]; //下面的代码使用逗号操作符一次更新两个变量 for (let i 0, j 9; i j; i, j--) {// ^console.log(a[${i}][${j}] ${a[i][j]}); } 2.5.10 一元运算符 //删除对象的属性如果成功返回true否则返回false delete object.property; delete object[propertyKey]; delete objectName[index];typeof操作符返回一个字符串该字符串指示未求值操作数的类型 2.5.11 关系运算符 关系运算符比较其操作数并根据比较是否为真返回布尔值。 //如果指定的属性在指定的对象中则in操作符返回true。 //其中propNameOrNumber是表示属性名称或数组索引的字符串、数字或符号表达式objectName是对象的名称 propNameOrNumber in objectName//如果指定的对象属于指定的对象类型则instanceof操作符返回true objectName instanceof objectType 2.5.12 基本表达式 this(代表对象本身) new(创建一个对象) super(调用父类的构造函数) //this script function validate(obj, lowval, hival) {if (obj.value lowval || obj.value hival) {console.log(Invalid Value!);} } /script pEnter a number between 18 and 99:/p input typetext nameage size3 onChangevalidate(this, 18, 99); / 2.6 数值和日期 2.6.1 数值 //八进制 076//当0后面的数字小于8时被解释为八进制否则解释为10进制这种严格模式下报错 0o76//正规语法使用该方式//二进制 0b10000000000000000000000000000000 // 2147483648 0b01111111100000000000000000000000 // 2139095040//十六进制 0x123456789ABCDEF2.6.2 数值对象 Number有一些常量可以使用 let n 1234 let n1 0.001234 //指数表示 console.log (n.toExponential(3)); //1.234e3 console.log (n1.toExponential(3)); //1.234e-3 //保留小数位数 console.log (n.toFixed(2));//1234.00 console.log (n1.toFixed(2));//0.00 //精度位数 console.log (n.toPrecision(3));//1.23e3 console.log (n1.toPrecision(3));//0.001232.6.3 Math对象 注意所有的数学三角方法都以弧度为参数 //Math.floor()向下取整,返回小于或等于参数的最大整数 console.log(Math.floor(5.95));// Expected output: 5 console.log(Math.floor(-5.05));// Expected output: -6//Math.ceil()向上取整返回大于或等于参数的最小整数 console.log(Math.ceil(0.95));// Expected output: 1 console.log(Math.ceil(-7.004));// Expected output: -7//Math.round(),四舍五入返回最接近的整数 console.log(Math.round(5.95), Math.round(5.5), Math.round(5.05));// Expected output: 6 6 5 console.log(Math.round(-5.05), Math.round(-5.5), Math.round(-5.95));// Expected output: -5 -5 -6//Math.fround()返回最接近的32位单精度浮点数表示形式 console.log(Math.fround(5.5));// Expected output: 5.5 console.log(Math.fround(5.05));// Expected output: 5.050000190734863 console.log(Math.fround(5));// Expected output: 5 console.log(Math.fround(-5.05));// Expected output: -5.050000190734863//Math.trunc()直接删除小数部分通过删除任何小数位数返回数字的整数部分 console.log(Math.trunc(0.123));// Expected output: 0 2.6.4 BigInts 2.6.5 日期对象 JavaScript没有日期数据类型。但是您可以使用Date对象及其方法在应用程序中处理日期和时间 2.6.5.1 创建一个日期对象 const dateObjectName new Date([parameters]); 不带new关键字调用Date将返回一个表示当前日期和时间的字符串 参数解释 不带参数表示创建一个当下的日期和时间例new Date()字符串YYYY-MM-DDTHH:mm:ss.sssZ例new Date(“1995-12-25”)如果省略小时、分钟或秒则该值将设置为零年月日设置例new Date(1995, 11, 25)年月日时分秒设置例new Date(1995, 11, 25, 9, 30, 0) 2.6.5.2 日期对象的方法 方法分为几大类 ”set“类设置日期和时间”get“类获取日期和时间”to“类返回字符串日期和时间”set“类设置日期和时间”parse “和UTC类解析日期时间 有一个getDay方法返回星期几但是没有相应的setDay方法因为星期几是自动设置的 各种值的取值范围 秒和分钟0-59小时0-23星期0-6日期1-31月0-11年自1990开始 //parse方法用于将日期字符串中的值分配给现有的date对象 const ipoDate new Date(); ipoDate.setTime(Date.parse(Aug 9, 1995));2.7 文本格式化 2.7.1 字符串对象 String对象是字符串原语数据类型的包装器 2.7.1.1 对象方法 方法解释charAt(index)返回一个指定索引处的字符。超出索引范围返回一个空字符串。charCodeAt(index)0 ~ 65535之间的整数。表示指定索引处字符的UTF-16码单位值。超出索引范围返回NaN。codePointAt(index)一个非负整数当unicode值为两个16位代码单位时使用。超出索引范围返回undefined。indexOf(searchString[, position])查找到的searchString第一次出现的索引如果没有找到则为-1。大于或等于position默认0位置lastIndexOf(searchString[, position])返回指定子字符串最后出现的索引startsWith()确定该字符串是否以指定字符串的字符开头并根据需要返回true或falseendsWith()确定字符串是否以该字符串的字符结束并根据需要返回true或false。includes()执行区分大小写的搜索以确定给定字符串是否可以在此字符串中找到并根据情况返回true或falseconcat(str1, str2, /* …, */ strN)将字符串参数连接到此字符串并返回一个新字符串参数可以是多个字符串split(separator[, limit])接受一个模式并通过搜索该模式将该字符串划分为有序的子字符串列表将这些子字符串放入数组并返回该数组slice(indexStart[, indexEnd])提取该字符串的一部分并将其作为新字符串返回而不修改原始字符串。可接收负参数substring(indexStart[, indexEnd])返回从开始索引到不包括结束索引的字符串部分如果没有提供结束索引则返回到字符串的末尾。自动将较小的参数作为开始索引较大的参数作为结束索引match(regexp)检索与正则表达式匹配该字符串的结果返回数组matchAll(regexp)返回一个迭代器其中包含与正则表达式匹配的字符串的所有结果包括捕获组replace(pattern, replacement)返回一个新字符串其中包含一个、一些或所有匹配的模式该模式被替换replaceAll(pattern, replacement)返回一个新字符串其中模式的所有匹配都被替换。模式可以是字符串或RegExp替换可以是要为每次匹配调用的字符串或函数。原始字符串保持不变。search(regexp)执行正则表达式与该字符串之间的匹配搜索返回字符串中第一个匹配的索引toLowerCase()返回转换为小写的字符串。toUpperCase()返回转换为大写的字符串。normalize(form)返回该字符串的Unicode规范化形式。form的值NFC, NFD, NFKC, or NFKDrepeat(count)构造并返回一个新字符串其中包含该字符串的指定数量的连接在一起的副本trim()从字符串的两端删除空白并返回一个新字符串而不修改原始字符串。 2.7.1.2 多行模板字面量 console.log(string text line 1 string text line 2); // string text line 1 // string text line 2const five 5; const ten 10; console.log(Fifteen is ${five ten} and not ${2 * five ten}.); // Fifteen is 15 and not 20.2.7.2 国际化 2.7.2.1 时间和日期格式化 Intl.DateTimeFormat对象用于格式化日期和时间 2.7.2.2 数值格式化 Intl.NumberFormat对象格式化数值 2.7.2.3 整理字符串 Intl.Collator对于比较和排序字符串有用 2.8 正则表达式 2.8.1 创建一个正则表达式 两种方式创建 使用字面量const re /abc/;调用RegExp对象的构造函数const re new RegExp(abc); 当您知道正则表达式模式将发生变化或者您不知道该模式并从其他源(例如用户输入)获取该模式时请使用构造函数 2.8.2 写一个正则表达式模板 2.8.2.1 断言类 断言包括边界它指示行和单词的开始和结束以及以某种方式指示可能匹配的其他模式(包括向前查找、向后查找和条件表达式)。 边界类断言 单词边界它表示的是单词字符字母、数字或下划线和非单词字符之间的位置或者单词字符和字符串的开始或结束之间的位置 字符串的开始和结束被认为是非单词 字符解释^匹配输入的开头$匹配输入的结尾\b匹配单词边界\B匹配非单词边界。例如两个字母之间或两个空格之间 其他类断言 字符解释x(?y)只有当x后面跟y时才匹配xx(?!y)只有当“x”后面没有“y”时才匹配“x”(?y)x仅当“x”前面有“y”时匹配“x”(?!y)x仅当“x”前面没有“y”时匹配“x”。 2.8.3.2 字符类 区分不同类型的字符 字符解释[xyz] [a-c]匹配任何一个包含的字符。连字符指定一个字符范围如连字符作为方括号内的第一个或最后一个字符为匹配字符[^xyz] [^a-c]它匹配没有括在方括号中的任何内容。连字符指定一个字符范围连字符在^后面的第一个字符或方括号内的最后一个字符则将其作为文字连字符作为普通字符包含在字符类中.匹配除行终止符以外的任何单个字符。在字符类中点失去了它的特殊含义而与文字点匹配\d匹配任何数字等价于[0-9]\D匹配任何非数字等价于[^0-9]\w匹配字母数字下划线等价于[A-Za-z0-9_]\W匹配非字母数字下划线等价于[^A-Za-z0-9_]\s匹配单个空白字符包括空格、制表符、表单换行、换行和其他Unicode空格\S匹配非单个空白字符\t匹配水平制表符\r匹配回车符。\n匹配换行\v匹配垂直制表符\f表单换行\0匹配一个NUL字符。后面不要跟另一个数字\xhh用代码hh(两个十六进制数字)匹配字符\uhhhh匹配一个UTF-16编码单元值为hhhh(四个十六进制数字)。\u{hhhh} \u{hhhhh}(仅当设置了u标志时。)用Unicode值Uhhhh或Uhhhh(十六进制数字)匹配字符\指示后面的字符应该被特殊处理或者“转义”xy 2.8.4.3 组和反向引用类 组将多个模式作为一个整体进行分组在使用正则表达式模式对字符串进行匹配时捕获组提供了额外的子匹配信息。 反向引用引用在同一正则表达式中先前捕获的组 字符解释(x)匹配x并记住匹配项使用exec函数时括号内会单独匹配一次(?Namex)匹配“x”并将其存储在返回的匹配项的groups属性中名称为 name (?:x)匹配“x”但不记得匹配\n反向引用括号中的组例如/apple()\sorange\1/。匹配apple, orange, cherry, peach中的apple, orange。\kName与指定的Named捕获组匹配的最后一个子字符串的反向引用。类似于\n 2.8.5.4 数量类 指示要匹配的字符或表达式的数量 字符解释x*匹配零次或多次。0x匹配一次或多次。1x?匹配零次或一次。0或1x{n}精确匹配x出现了n次的x{n,}匹配x至少出现了n的x{n,m}匹配至少出现n次最多出现m次x*? x? x?? x{n}? x{n,}? x{n,m}?默认为贪婪模式加上后为非贪婪模式 2.8.5.5 高级搜索标志 const re /pattern/flags; 标志描述d为子字符串匹配生成索引j全局搜索i不区分大小写的搜索m允许^和$在换行符旁边匹配s允许.匹配换行符u将模式视为Unicode码点序列v升级到具有更多Unicode功能的u模式y执行从目标字符串的当前位置开始匹配的“粘性”搜索。 2.8.3 使用正则表达式 方法描述exec()执行对字符串中的匹配项的搜索。它返回一个信息数组如果不匹配则返回null。test()测试字符串中的匹配项。它返回真或假match()返回一个包含所有匹配项(包括捕获组)的数组如果没有找到匹配项则返回null。matchAll()返回一个包含所有匹配项(包括捕获组)的迭代器。search()测试字符串中的匹配项。它返回匹配项的索引如果搜索失败则返回-1。replace()执行对字符串中的匹配项的搜索并用替换子字符串替换匹配的子字符串replaceAll()对字符串中的所有匹配项执行搜索并用替换子字符串替换匹配的子字符串。split()使用正则表达式或固定字符串将字符串分解为子字符串数组。 当您想知道是否在字符串中找到匹配时请使用test()或search()方法 要获得更多信息(但执行速度较慢)请使用exec()或match()方法 2.8.4 工具 RegExr一个学习、构建和测试正则表达式的在线工具 Regex tester一个在线正则表达式构建器/调试器 Regex interactive tutorial一个在线互动教程手册和广场 Regex visualizer一个在线可视化正则表达式测试器 2.9 索引集合类 2.9.1 创建一个数组 //创建一个有元素的数组 const arr1 new Array(element0, element1, /* …, */ elementN); const arr2 Array(element0, element1, /* …, */ elementN); const arr3 [element0, element1, /* …, */ elementN]; //创建一个有长度的空数组 const arr1 new Array(arrayLength); const arr2 Array(arrayLength); const arr3 []; arr3.length arrayLength;const wisenArray Array.of(9.3);2.9.2 引用数组元素 2.9.3 填充一个数组 2.9.3.1 理解length 在实现层JavaScript的数组实际上将其元素存储为标准对象属性使用数组索引作为属性名 长度属性是特殊的。它的值总是一个正整数大于最后一个元素的索引(如果存在) 你也可以给length属性赋值写入小于存储项数的值将截断数组。写0将把它清空 2.9.3.2 遍历数组 for循环和forEach 请注意在定义数组时省略的数组元素在使用forEach迭代时不会列出但在将undefined手动赋值给该元素时才会列出 const sparseArray [first, second, , fourth];//不会列出 const nonsparseArray [first, second, undefined, fourth];//会列出不建议使用for…in循环这样会列出普通元素和所有可枚举属性 2.9.3.3 数组的方法 方法说明示例let myArray [“1”, “2”, “3”];concat()连接两个或多个数组并返回新数组const newArray myArray.concat(“a”, “b”, “c”,[1,2]);join()将一个数组的所有元素连接成一个字符串const list myArray.join( - );push()将一个或多个元素添加到数组的末尾并返回数组的结果长度myArray.push(“3”);pop()从数组中删除最后一个元素并返回该元素const last myArray.pop();shift()从数组中删除第一个元素并返回该元素。const first myArray.shift();unshift()将一个或多个元素添加到数组的前面并返回数组的新长度myArray.unshift(“4”, “5”);slice()提取数组的一部分并返回一个新数组。myArray.slice(1, 2);at()at()方法返回数组中指定索引处的元素如果索引超出范围则返回undefined。它特别用于从数组末尾访问元素的负索引myArray.at(-2);splice()从数组中删除元素并(可选地)替换它们。它返回从数组中删除的项myArray.splice(1, 3, “a”, “b”, “c”, “d”);1开始移除3个元素并用后面参数填充reverse()将数组中的元素调换位置:第一个数组元素变成最后一个最后一个元素变成第一个。它返回对数组的引用myArray.reverse();flat()返回一个新数组其中所有子数组元素递归地连接到其中直至指定的深度let myArray [1, 2, [3, 4]];myArray myArray.flat();//[1, 2, 3, 4]sort()对数组中的元素进行排序并返回对该数组的引用。可以带回调函数自定义比较方式myArray.sort();indexOf()返回第一个匹配项的索引myArray.indexOf(“1”)lastIndexOf()方法的工作方式与indexOf类似但从末尾开始并向后搜索myArray.lastIndexOf(“1”)forEach()对每个数组项执行回调并返回undefined。myArray.forEach((element) { console.log(element); });map()返回对每个数组项执行回调的返回值的新数组。const a2 a1.map((item) item.toUpperCase());flatMap()在map()之后运行深度为1的flat()。filter()返回一个新数组其中包含回调返回true的项目const a2 a1.filter((item) typeof item “number”);find()返回回调返回true的第一个项const i a1.find((item) typeof item “number”);findLast()返回回调返回true的最后一项。findIndex()返回回调返回true的第一个项的索引。findLastIndex()返回回调返回true的最后一项的索引。every()如果回调函数对数组中的每个项都返回true则every()方法返回truesome()如果回调函数对数组中至少一项返回true则some()方法返回true。reduce()应用回调callback(accumulator, currentValue, currentIndex, array)。此回调的返回值会再次赋值给accumulatorreduceRight()工作方式与reduce()类似但从最后一个元素开始 2.9.4 数组变换 您可以在数组和其他数据结构之间来回转换 let students [{name:张三,sex:男},{name:王五,sex:男},{name:小三,sex:女},{name:李六,sex:男},{name:韩其,sex:男},{name:小美,sex:女},{name:小帅,sex:男}, ]//按照性别分组 const result Object.groupBy(students, ({ sex }) sex); console.log (result); //按照符合条件的分组 const result2 Object.groupBy(students, ({ name }) name.startsWith(小)); console.log (result2);2.9.5 稀疏数组 数组可以包含“空槽”这与填充值为undefined的槽不同 2.9.6 多维数组 数组可以嵌套这意味着一个数组可以包含另一个数组作为元素。使用JavaScript数组的这个特性可以创建多维数组 2.9.7 使用数组存储其他属性 数组也可以像对象一样用于存储相关信息 const arr [1, 2, 3]; arr.property value; console.log(arr.property); // value2.9.8 类数组对象 NodeList或函数体中的arguments对象表面上看起来和行为都像数组但并不共享它们的所有方法 数组方法不能在类数组对象上直接调用 但是你可以使用Function.prototype.call()间接调用它们 function printArguments() {Array.prototype.forEach.call(arguments, (item) {console.log(item);}); }2.10 键集合 2.10.1 Maps 2.10.1.1 Map对象 Map对象是一个简单的键/值映射可以按插入顺序迭代其元素 const sayings new Map(); sayings.set(dog, woof); sayings.set(cat, meow); sayings.set(elephant, toot); sayings.size; // 3 sayings.get(dog); // woof sayings.get(fox); // undefined sayings.has(bird); // false sayings.delete(dog); sayings.has(dog); // falsefor (const [key, value] of sayings) {console.log(${key} goes ${value}); } // cat goes meow // elephant goes tootsayings.clear(); sayings.size; // 0 2.10.1.2 对象和Map比较 对象的key可以是strings和symbols而map可以是任何值您可以轻松地获得Map的大小而您必须手动跟踪对象的大小map的迭代按照元素的插入顺序进行一个对象有一个原型所以在映射中有默认的键 let keyObj{} // 虽然看起来你可以使用数字作为对象的键但实际上这些键都被转换为了字符串 const obj {true:34,1:456,2:ww,keyObj:2 } for (let key of Object.keys(obj)) {console.log(key,typeof key); } console.log (obj); // 1类型是 string // 2类型是 string // true类型是 string // keyObj类型是 stringconst map new Map(); map.set(true,34) map.set(1,456) map.set(2,ww) map.set(keyObj,2) for (let key of map.keys()) {console.log(key,typeof key); } // true boolean // 1 number // 2 string // {} object以下三个技巧可以帮助你决定是使用Map还是Object: 当键在运行时都是未知的并且所有键有相同的类型所有值有相同的类型时使用map如果需要将原始值存储为键请使用 Map因为对象会将每个键都视为字符串当对单个元素进行操作的逻辑存在时使用Object 2.10.1.3 WeakMap对象 WeakMap是键/值对的集合其键必须是对象或未注册的符号具有任意JavaScript类型的值并且不会创建对其键的强引用 在WeakMap中作为键存在的对象不会阻止该对象被垃圾收集。一旦作为键使用的对象被收集它在任何WeakMap中的对应值也成为垃圾收集的候选者——只要它们没有在其他地方被强引用。 惟一可以用作WeakMap键的基本类型是symbol WeakMap不允许观察其键的活动这就是为什么它不允许枚举的原因。因此没有方法可以获取WeakMap中的键列表 WeakMap对象的一个用例是存储对象的私有数据或者隐藏实现细节 2.10.2 Sets 2.10.2.1 Set对象 集合对象是唯一值的集合。您可以按插入顺序迭代它的元素。Set中的值只能出现一次;这是唯一的集合的集合 const mySet new Set(); mySet.add(1); mySet.add(some text); mySet.add(foo);mySet.has(1); // true mySet.delete(foo); mySet.size; // 2for (const item of mySet) {console.log(item); } // 1 // some text2.10.2.2 Array和Set之间的转换 使用Array.from将一个集合转换成数组 Set对象存储唯一的值—因此在转换时将删除任何来自Array的重复元素! const set new Set() set.add(1) set.add(3) set.add(4) set.add(3)const arr Array.from(set) console.log (arr);//[1, 3, 4]2.10.2.3 Array 和 Set 的比较 通过arr.splice(arr.indexOf(val), 1)删除数组元素非常慢集合可以通过值直接删除元素而数组则需要使用splice基于元素索引在数组的indexOf中找不到值NaNSet 对象存储唯一值。你不需要手动跟踪重复项 2.10.1.3 WeakSet对象 弱集对象是可垃圾回收值的集合包括对象和未注册的符号。WeakSet中的值只能出现一次。它在WeakSet集合中是唯一的 WeakSet和Set的不同 与集合相反弱集只是对象或符号的集合而不是任何类型的任意值的集合WeakSet是弱的:对集合中对象的引用是弱保存的。如果对WeakSet中存储的对象没有其他引用则可以对它们进行垃圾收集。这也意味着集合中没有存储当前对象的列表WeakSet不可枚举 WeakSet对象的用例是有限的。它们不会泄漏内存因此使用DOM元素作为键并标记它们以进行跟踪是安全的 2.11 使用对象 对象是属性的集合属性是名称(或键)和值之间的关联。属性的值可以是一个函数在这种情况下属性被称为方法。 2.11.1 创建新对象 2.11.1.1 使用初始化器 对象初始化器也称为对象字面量 const obj {property1: value1, // property name may be an identifier2: value2, // or a numberproperty n: value3, // or a string };使用初始化器创建的对象称为普通对象因为它们是Object的实例而不是任何其他对象类型。一些对象类型有特殊的初始化语法——例如数组初始化和正则表达式字面量 2.11.1.2 使用构造函数 function Person(name, age, sex) {this.name name;this.age age;this.sex sex; } const rand new Person(Rand McKinnon, 33, M);您还可以使用class语法而不是function语法来定义构造函数 2.11.1.3 使用Object.create()方法 它允许您为想要创建的对象选择原型对象而不必定义构造函数。 // Animal properties and method encapsulation const Animal {type: Invertebrates, // Default value of propertiesdisplayType() {// Method which will display type of Animalconsole.log(this.type);}, };// Create new animal type called animal1 const animal1 Object.create(Animal);2.11.2 对象和属性 JavaScript对象具有与之关联的属性。对象属性基本上与变量相同除了它们与对象相关联而不是与作用域相关联。对象的属性定义了对象的特征 2.11.2.1 访问属性 str myString; myObj[str] This key is in variable str;console.log(myObj.str); // undefinedconsole.log(myObj[str]); // This key is in variable str console.log(myObj.myString); // This key is in variable str 2.11.2.2 枚举属性 for…in ,此方法遍历对象的所有可枚举字符串属性及其原型链。自己可枚举属性原型属性Object.keys()返回一个数组只枚举自己中的属性而不是原型链中的。自己可枚举属性Object.getOwnPropertyNames()返回一个数组只枚举自己中的属性而不管是否可枚举。自己可枚举属性自己不可枚举属性 2.11.2.3 删除属性 可以使用delete操作符删除非继承属 delete myobj.a; 2.11.3 继承 所有对象都至少继承一个其他对象。被继承的对象被称为原型继承的属性可以在构造函数的原型对象中找到 你可以使用prototype属性为通过某个构造函数创建的所有对象添加属性 Car.prototype.color red; console.log(car1.color); // red2.11.4 定义方法 方法的定义方式与普通函数的定义方式相同不同之处在于它们必须被赋值为对象的属性 objectName.methodName functionName;const myObj {myMethod: function (params) {// do something},// this works too!myOtherMethod(params) {// do something else}, };2.11.5 定义getter和setter getter是一个与属性相关联的函数用于获取特定属性的值。setter是与属性相关联的函数用于设置特定属性的值。它们一起可以间接地表示属性的值。 定义时以关键字get或set作为前缀。getter方法不需要参数而setter方法只需要一个参数(要设置的新值) const myObj {a: 7,get b() {return this.a 1;},set c(x) {this.a x / 2;}, };console.log(myObj.a); // 7 console.log(myObj.b); // 8, returned from the get b() method myObj.c 50; // Calls the set c(x) method console.log(myObj.a); // 25 也可以使用object . defineproperties()方法在对象创建后随时将getter和setter添加到对象中 const myObj { a: 0 };Object.defineProperties(myObj, {b: {get() {return this.a 1;},},c: {set(x) {this.a x / 2;},}, });myObj.c 10; // Runs the setter, which assigns 10 / 2 (5) to the a property console.log(myObj.b); // Runs the getter, which yields a 1 or 6 2.11.6 比较对象 对象是一种引用类型。两个不同的对象永远不会相等即使它们具有相同的属性。只有将同一对象引用与自身进行比较才会产生true 2.12 使用类 在JavaScript中类主要是对现有原型继承机制的抽象——所有模式都可以转换为基于原型的继承。 类本身也是普通的JavaScript值并且有自己的原型链。实际上大多数普通JavaScript函数都可以用作构造函数—使用new操作符和构造函数来创建新对象。 2.12.1 类概述 类的基本 类创建对象使用new操作符每一个对象都有一些通过类添加的属性数据方法类存储一些自己的属性数据方法被用于和实例交互 类的三大关键特征 构造函数实例方法和实例字段静态方法和静态字段 2.12.2 声明类 基本声明结构 class MyClass {// 构造函数constructor() {// 构造函数体}// 实例字段myField foo;// 实例方法myMethod() {// 方法体}// 静态字段static myStaticField bar;// 静态方法static myStaticMethod() {// 方法体}// 静态代码块static {// 静态初始化代码}// 私有属性#myPrivateField bar; } 与函数声明不同类声明不会被提升(或者在某些解释中会被提升但有暂时死区限制)这意味着在声明类之前不能使用它。 类声明还可以使用表达式 const MyClass class {// Class body... }; 2.12.3 构造函数 也许类最重要的工作是充当对象的“工厂”。在类中实例创建是由构造函数完成的。 class Color {constructor(r, g, b) {// Assign the RGB values as a property of this.this.values [r, g, b];} } 建议不要从构造函数返回任何值——因为如果返回一个非原始值它将成为new表达式的值而this的值将被删除 2.12.4 实例方法 class Color {constructor(r, g, b) {this.values [r, g, b];}getRed() {return this.values[0];} }const red new Color(255, 0, 0); console.log(red.getRed()); // 2552.12.5 私有字段 在面向对象编程中有一种哲学叫做“封装”。这意味着您不应该访问对象的底层实现而应该使用抽象良好的方法与之交互 私有字段是以#(散列符号)为前缀的标识符。哈希是字段名称的组成部分这意味着私有属性永远不会与公共属性发生名称冲突 为了在类的任何地方引用私有字段必须在类体中声明它(不能动态地创建私有属性)。除此之外私有字段几乎等同于普通属性 注意在Chrome控制台中运行的代码可以在类的外面访问私有属性。这是一个仅针对devtools的JavaScript语法限制的放松 在对属性进行赋值时往往需要在函数中进行合法性验证才允许赋值。但是如果属性不是私有属性则外部可以直接访问属性更改其值而绕过合法检查 类中访问不存在的私有属性会抛出错误而不是像普通属性那样返回未定义 方法、getter和setter也可以是私有的。当你有一些复杂的事情需要类在内部完成但不允许代码的其他部分调用时它们是有用的。 2.12.6 访问器字段 //看起来好像对象有一个名为red的属性——但实际上实例中不存在这样的属性!只有两个方法但它们都带有get和set前缀这使得它们可以像属性一样被操作 //如果一个字段只有getter而没有setter那么它实际上是只读的 class Color {constructor(r, g, b) {this.values [r, g, b];}get red() {return this.values[0];}set red(value) {this.values[0] value;} }const red new Color(255, 0, 0); red.red 0; console.log(red.red); // 0 2.12.7 公有字段 字段通常被设计成独立于构造函数的参数。 公共字段几乎等同于为this分配一个属性 class MyClass {luckyNumber Math.random(); } console.log(new MyClass().luckyNumber); // 0.5 console.log(new MyClass().luckyNumber); // 0.3//和上面等价 class MyClass {constructor() {this.luckyNumber Math.random();} } 2.12.8 静态属性 静态属性是在类本身上定义的一组类特性而不是在类的单个实例上定义。这些功能包括: 静态方法静态字段静态getter和setter 静态属性与实例属性非常相似不同之处在于: 静态的前缀都是static静态的不能由实例访问 还有一个称为静态初始化块的特殊构造它是在类首次加载时运行的代码块。 静态初始化块几乎等同于在声明类之后立即执行一些代码。唯一的区别是它们可以访问静态私有属性 2.12.9 扩展和继承 一个对象可以“借用”另一个对象的大部分行为同时用自己的逻辑重写或增强某些部分 派生类可以访问父类的所有公共属性。在JavaScript中派生类是用extends子句声明的该子句指出它是从哪个类派生的。 //我们调用super(r, g, b)。在访问this之前调用super()是语言要求 //super()调用调用父类的构造函数来初始化this -这里它大致相当于this new Color(r, g, b) //您可以在super()之前有代码但您不能在super()之前访问this class ColorWithAlpha extends Color {#alpha;constructor(r, g, b, a) {super(r, g, b);this.#alpha a;}get alpha() {return this.#alpha;}set alpha(value) {if (value 0 || value 1) {throw new RangeError(Alpha value must be between 0 and 1);}this.#alpha value;} }派生类也可以覆盖父类的方法。例如所有类都隐式继承Object类该类定义了一些基本方法如toString()。然而基本的toString()方法是出了名的无用因为它在大多数情况下打印[object object] 静态方法也会相互继承因此您也可以覆盖或增强它们 派生类不能访问父类的私有字段——这是JavaScript私有字段“硬私有”的另一个关键方面。私有字段的作用域限定在类主体本身不授予对任何外部代码的访问权限 2.13 使用promises Promise 是一个对象代表了一个异步操作的最终完成或者失败 2.13.1 链式调用 //果你的错误处理代码对所有步骤都是相同的你可以把它附加到链的末尾: doSomething().then((result) doSomethingElse(result)).then((newResult) doThirdThing(newResult)).then((finalResult) {console.log(Got the final result: ${finalResult});}).catch(failureCallback);2.13.2 错误处理 现在所有的错误都由链末尾的catch()方法处理如果不使用async/await几乎不需要使用try/catch 如果一个 Promise 的拒绝事件没有被任何处理程序处理它会冒泡到调用堆栈的顶部主机需要将其显示出来。在网页上每当一个 Promise 被拒绝全局范围内通常是窗口或者如果在 web worker 中使用它是 Worker 或其他基于 worker 的接口会发送两个事件之一。这两个事件是 unhandledrejection当Promise 被拒绝但没有可用的拒绝处理程序时发送rejectionhandled当处理程序附加到已被拒绝的Promise 时发送该Promise 已导致unhandledrejection事件. nodejs和浏览器有些许差异注意事件名的大小写 process.on(unhandledRejection, (reason, promise) {// Add code here to examine the promise and reason values });2.13.3 组合 有四种组合工具可用于并发运行异步操作 四个都接受Promise的可迭代对象作为输入并返回一个Promise Promise.all() 当所有输入的promise都实现时(包括传递空可迭代对象时)返回的promise就会实现并带有一个实现后数组 当输入的任何一个承诺被拒绝时它就会拒绝这是第一个拒绝原因。 总结都成功时才成功任何一个失败都会失败 Promise.allSettled() 当所有输入的promise都完成时(包括传递空可迭代对象时)这个返回的promise就会完成并使用一个对象数组来描述每个promise的结果 总结总是成功 Promise.any() 只要其中一个成功返回成功并携带第一个成功返回值 总结所有失败才失败返回拒绝原因的数组 Promise.race() 这个返回的承诺与第一个承诺的最终状态一致。 总结是在任何一个 Promise 完成无论成功还是失败时就完成。 我们可以同时开始操作然后像这样等待它们全部完成: Promise.all([func1(), func2(), func3()]).then(([result1, result2, result3]) {// use result1, result2 and result3 });2.13.4 旧回调API创建promises 在理想情况下所有异步函数都已经返回promises。不幸的是一些api仍然期望以旧的方式传递成功和/或失败回调。最明显的例子是setTimeout()函数 //混合旧式的回调和承诺是有问题的。如果saySomething()失败或包含编程错误则不会捕获它。这是setTimeout的内在设计 setTimeout(() saySomething(10 seconds passed), 10 * 1000); //index.js:1 Uncaught ReferenceError: saySomething is not defined幸运的是我们可以将setTimeout包装在一个promise中。最佳实践是在尽可能低的级别包装接受回调的函数然后不再直接调用它们 const wait (ms) new Promise((resolve) setTimeout(resolve, ms));wait(10 * 1000).then(() saySomething(10 seconds)).catch(failureCallback);2.13.5 时间 Promise回调作为微任务处理而setTimeout()回调作为任务队列处理 const wait (ms) new Promise((resolve) setTimeout(resolve, ms));wait(0).then(() console.log(4)); Promise.resolve().then(() console.log(2)).then(() console.log(3)); console.log(1); // 1, 2, 3, 42.14 类型数组 JavaScript类型数组是类似于数组的对象它提供了在内存缓冲区中读写原始二进制数据的机制。 它们为开发人员提供了操作二进制数据的熟悉接口。这在与平台特性交互时非常有用例如音频和视频操作、使用WebSockets访问原始数据等等。 在类型化数组上调用array . isarray()将返回false。此外并不是所有普通数组可用的方法都被类型化数组支持(例如push和pop) JavaScript的类型化数组将实现分为缓冲区和视图 为了访问缓冲区中的内存你需要使用视图 2.14.1 缓冲区 缓冲区是表示数据块的对象它本身没有格式也不提供访问其内容的机制 缓冲区有两种类型: ArrayBufferSharedArrayBuffer 缓冲区支持以下操作: 分配一旦新的缓冲区被创建新的内存区域被分配并初始化为0复制使用slice()方法您可以有效地复制内存的一部分而无需创建视图来手动复制每个字节转移使用transfer()和transferToFixedLength()方法您可以将内存范围的所有权转移到一个新的缓冲区对象。SharedArrayBuffer不能被转移调整大小使用resize()方法您可以调整内存区域的大小在maxByteLength限制范围内SharedArrayBuffer只能增长不能收缩。 2.14.2 视图 视图提供了一个上下文——也就是数据类型起始偏移量和元素数量。 目前有两种主要的视图: 类型化数组视图提供实用程序方法允许您方便地转换二进制数据层次更低允许对数据的访问方式进行粒度控制 视图有以下属性 buffer视图引用的底层缓冲区byteOffset视图从其缓冲区开始的偏移量以字节为单位。byteLength视图的长度以字节为单位。 2.14.2.1 类型数组视图 TypeValue RangeSize in bytesWeb IDL typeInt8Array-128 to 1271byteUint8Array0 to 2551octetUint8ClampedArray0 to 2551octetInt16Array-32768 to 327672shortUint16Array0 to 655352unsigned shortInt32Array-2147483648 to 21474836474longUint32Array0 to 42949672954unsigned longFloat32Array-3.4e38 to 3.4e384unrestricted floatFloat64Array-1.8e308 to 1.8e3088unrestricted doubleBigInt64Array-263 to 263 - 18bigintBigUint64Array0 to 264 - 18bigint 所有类型化数组视图都有相同的方法和属性由TypedArray类定义 类型化数组原则上是固定长度的因此不能使用可能改变数组长度的数组方法。这些包括 pop, push, shift, splice, 和 unshift 此外flat是不可用的因为没有嵌套的类型数组相关的方法包括concat和flatMap没有很好的用例所以不可用。toSpliced也不可用 除以上外其他数组方法在array和TypedArray之间共享 TypedArray有额外的set和subarray方法可以优化处理查看同一缓冲区的多个类型数组 set()方法允许使用来自另一个数组或类型化数组的数据同时设置多个类型化数组索引 subarray()方法创建一个新的类型化数组视图该视图引用与原始类型化数组相同的缓冲区但范围更窄 与常规数组类似您可以使用括号表示法访问类型化数组元素 越界索引访问总是返回undefined而不实际访问对象上的属性 任何写越界属性的尝试都没有效果:它不会抛出错误但也不会改变缓冲区或类型化数组 类型化数组索引似乎是可配置和可写的但任何更改其属性的尝试都将失败 const typeArrayView8 new Uint8Array([1,2,3]) console.log (typeArrayView8[2]); // log 32.14.2.2 DataView DataView是一个低级接口它提供了一个getter/setter API用于向缓冲区读取和写入任意数据。 DataView不需要对齐;多字节读写可以在任何指定的偏移量开始 const dataView8 new DataView(new ArrayBuffer(3)); dataView8.setInt8(0, 1, true); dataView8.setInt8(1, 2, true); dataView8.setInt8(2, 3, true); console.log (dataView8.getInt8(2));//log 3类型数组视图TypedArray和DataView都是操作ArrayBuffer的接口但它们之间存在一些差异和不同的使用场景。 相较于 TypedArrayDataView 对于 ArrayBuffer 的操作更加灵活。我们可以发现在 TypedArray 中操作二进制 ArrayBuffer 时每个元素占用的字节大小是固定的要么每个元素占用8位、16位或者32位。例如如果你创建一个Int32Array类型数组视图来操作一个ArrayBuffer那么每个元素都会占用32位4个字节。 而 DataView 对于 ArrayBuffer 的操作就显得更加灵活了我们可以通过 DataView 从 ArrayBuffer 中读取或写入各种不同大小的元素。例如你可以使用DataView的getUint8方法读取一个8位的无符号整数或者使用setFloat32方法写入一个32位的浮点数。 所以如果你需要在同一个ArrayBuffer中存储不同类型或不同大小的元素那么DataView可能是更好的选择。如果你只需要存储同一种类型的元素那么类型数组视图可能更简单、更直观。 2.14.3 类型化数组的api FileReader.prototype.readAsArrayBuffer()方法开始读取指定Blob或File的内容fetch()请求体可以是类型化数组或ArrayBufferImageData.data是Uint8ClampedArray表示一个一维数组包含RGBA顺序的数据整数值在0到255之间 2.14.4 示例 //开辟一块内存空间空间大小两个字节 const buffer new ArrayBuffer(2);//创建一个8位的视图 const int8View new Int8Array(buffer);//给内存单元赋值 int8View[0] 1; int8View[1] 8;console.log(int8View);//结果内存中存储为十六进制 01 08//创建一个16位的视图 const int16View new Int16Array(buffer);console.log(int16View);//由于是16位视图。要取两个字节但是计算时需要高低字节对调 08 01 2049读成字符文本 const buffer new ArrayBuffer(8); const uint8 new Uint8Array(buffer); // Data manually written here, but pretend it was already in the buffer uint8.set([228, 189, 160, 229, 165, 189]); const text new TextDecoder().decode(uint8); console.log(text); // 你好下面的代码使用String.fromCharCode()方法读取UTF-16文本: const buffer new ArrayBuffer(8); const uint16 new Uint16Array(buffer); // Data manually written here, but pretend it was already in the buffer uint16.set([0x4f60, 0x597d]); const text String.fromCharCode(...uint16); console.log(text); // 你好转换为一般数组 const typedArray new Uint8Array([1, 2, 3, 4]); const normalArray Array.from(typedArray);//以及扩展语法: const typedArray new Uint8Array([1, 2, 3, 4]); const normalArray [...typedArray]; 2.15 迭代器和生成器 迭代器和生成器带来了迭代的概念并且提供一个方法去自定义for…of循环的行为 2.15.1 迭代器 在JavaScript中迭代器是一个对象它定义了一个序列并可能在序列结束时返回一个值 function simpleRangeIterator(start, end, step 1) {//首先函数要返回一个对象return {[Symbol.iterator]() {// 返回一个符合迭代器协议的对象return {// next() 方法迭代器协议的一部next() {let result;if (start end) {result { value: start, done: false };start2;return result;}return { value: count, done: true };//done为true时遍历结束},};},}; }const it simpleRangeIterator(1, 20); for (const iterator of it) {console.log(iterator); }2.15.2 生成器函数 生成器语法function* 该函数可以根据需要调用多次每次都返回一个新的Generator。每个生成器只能迭代一次 使用生成器函数 function* makeRangeIterator(start 0, end Infinity, step 1) {console.log (----------);let iterationCount 0;for (let i start; i end; i step) {iterationCount;yield i;}return iterationCount; }//生成器函数最初并不执行它们的代码makeRangeIterator中 const iter makeRangeIterator(1, 10, 2);//它返回一种特殊类型的迭代器称为Generatorlet result iter.next();//调用生成器的next方法生成器中的代码makeRangeIterator中开始执行直到遇到yield就停止 while (!result.done) {console.log(result.value); // 1 3 5 7 9result iter.next(); }console.log(Iterated over sequence of size:, result.value); 2.15.3 可迭代的 为了可迭代对象必须实现iterator方法这意味着该对象必须有一个属性Symbol.iterator 2.15.4 高级生成器 next()方法还接受一个值该值可用于修改生成器的内部状态。传递给next()的值将被yield接收 2.16 元编程 Proxy和Reflect对象允许您拦截和定义基本语言操作的自定义行为(例如属性查找、赋值、枚举、函数调用等)。在这两个对象的帮助下您可以在JavaScript的元级别进行编程 2.16.1 代理 允许您拦截某些操作并实现自定义行为 //被代理对象 const target {a:1 }//处理函数 const handler {get(target, prop) {return prop in target ? target[prop] : 属性未定义;//代理后更改了属性不存在的行为}, };//设置一个代理 const p new Proxy(target, handler);//意思就是p把target代理了具有target的一切属性但是在执行对象一些行为时可以用处理函数捕捉并处理后返回 console.log(p.a, p.b); //代理后 1, 属性未定义 console.log (target.a,target.b);//未代理 1, undefined术语 处理器包含陷阱的占位符对象陷阱提供属性访问的方法这类似于操作系统中的陷阱概念getter和setter等都是陷阱目标代理虚拟化的对象不变性当实现自定义操作时必须保持某些基本操作的语义不变这些不变的语义称为不变量。如果一个代理Proxy的处理程序handler违反了这些不变量就会抛出一个TypeError 2.16.2 处理器和陷阱 //被代理对象 const target {a: 1,b: 2, };/*** target目标对象。* prop要设置或获取到的属性名。* value被设置的值。* receiver最初被调用的对象。通常是代理本身。* prototype需要设置的原型对象* fun目标对象被调用的函数。* thisArg被调用时的this值* argumentsList被调用时的参数列表是一个类数组对象* constructFun目标对象被调用的构造函数* args一个类数组对象包含了调用构造函数时传递的参数。* */ //处理函数 const handler {getPrototypeOf(target) {/*** 获取对象的原型* * 拦截以下操作* Object.getPrototypeOf()* Reflect.getPrototypeOf()* __proto__* Object.prototype.isPrototypeOf()* instanceof*/return Object.getPrototypeOf(target);},setPrototypeOf(target, prototype) {/*** 设置对象的原型* * 拦截以下操作* Object.setPrototypeOf()* Reflect.setPrototypeOf()*/return Object.setPrototypeOf(target, prototype);},isExtensible(target) {/*** 判断对象是否是可扩展的可扩展就可所以添加新属性* * 拦截以下操作* Object.isExtensible()* Reflect.isExtensible()*/return Reflect.isExtensible(target);},preventExtensions(target) {/*** 阻止对象可扩展* * 拦截以下操作* Object.preventExtensions()* Reflect.preventExtensions()*/return Reflect.preventExtensions(target);},getOwnPropertyDescriptor(target, prop) {/*** 返回指定对象上一个自有属性对应的属性描述符* * 拦截以下操作* Object.getOwnPropertyDescriptor()* Reflect.getOwnPropertyDescriptor()*/return Object.getOwnPropertyDescriptor(target, prop);},defineProperty(target, prop, descriptor) {/*** 直接在一个对象上定义新属性或修改对象上的现有属性并返回这个对象* * 拦截以下操作* Object.defineProperty()* Reflect.defineProperty()*/return Object.defineProperty(target, prop, descriptor);},has(target, prop) {/*** 检查代理对象Proxy的属性是否存在* * 拦截以下操作* foo in proxy* foo in Object.create(proxy)* Reflect.has()*/return Reflect.has(target, prop);},get(target, prop, receiver) {/*** 获得属性值* * 拦截以下操作* proxy[foo]* proxy.bar* Object.create(proxy)[foo]* Reflect.get()*/return target[prop];},set(target, prop, value, receiver) {/*** 修改属性值* * 拦截以下操作* proxy[foo] bar* proxy.foo bar* Object.create(proxy)[foo] bar* Reflect.set()*/return (target[prop] value);},deleteProperty(target, prop) {/*** 获取对象的原型* * 拦截以下操作* delete proxy[foo]* delete proxy.foo* Reflect.deleteProperty()*/if (prop in target) {delete target[prop];console.log(property removed: ${prop});}},ownKeys(target) {/*** 获取属性键的列表包括不可枚举属性和Symbol类型的属性* * 拦截以下操作* Object.getOwnPropertyNames()* Object.getOwnPropertySymbols()* Object.keys()* Reflect.ownKeys()*/return Reflect.ownKeys(target);},apply: function (fun, thisArg, argumentsList) {/*** 代理函数时用于拦截函数的调用* * 拦截以下操作* proxy(..args)* Function.prototype.apply()* Function.prototype.call()* Reflect.apply()*/return fun(argumentsList[0], argumentsList[1]) * 10;},construct(constructFun, args) {/*** 用于拦截构造函数的调用操作当使用new操作符调用代理作为构造函数时construct陷阱会被触发* * 拦截以下操作* new proxy(...args)* Reflect.construct()*/return new constructFun(...args);}, };//设置一个代理 const p new Proxy(target, handler);2.16.3 可撤销的代理 Proxy.revocable()可以创建可撤销的代理这意味着可以使用revoke()函数撤销代理并关闭代理 //被代理对象 const target {a: 1,b: 2, };//处理函数 const handler {get(target, prop, receiver) {return 属性值:${prop}${target[prop]};},};const revocable Proxy.revocable(target, handler) const p1 revocable.proxyconsole.log (p1.a);//属性值:a1 revocable.revoke(); console.log (p1.a);//TypeError: Cannot perform get on a proxy that has been revoked2.16.4 反射 Reflect是一个内置对象为可拦截的JavaScript操作提供方法 Reflect不是一个函数对象使用时需要调用其静态方法 //一个更好的apply()函数 function fun(x){console.log (x,------); } fun(1);//1 ------ Function.prototype.apply.call(fun, undefined, [2]);//2 ------ Reflect.apply(fun, undefined, [3]);//3 ------检查属性定义是否成功 Reflect的方法与其它方式执行同样的操作相比返回结果更为一致且可预测。 例如Reflect.defineProperty()在失败时返回false而Object.defineProperty()在失败时抛出一个错误。 2.17 模块 2.17.1 基本文件结构 index.html main.js modules/canvas.jssquare.js使用mjs后缀优势 这有利于清晰也就是说它清楚地表明哪些文件是模块哪些是常规JavaScript它确保你的模块文件被运行时(如Node.js)和构建工具(如Babel)解析为模块 但是还是使用js后缀 大多数服务器已经为.js文件设置了正确的MIME类型但还没有为.mjs文件设置有些工具可能永远不支持.mjsscript typemodule 属性被用来标记所指向的是一个模块 2.17.2 导出模块属性 要访问模块特性首先要做的就是导出它们。这是使用export语句完成的 使用它最简单的方法是将它放在你想要导出模块的任何项的前面 export const name square; export function draw() {}你可以导出函数。varletconst变量和类。它们需要被放在顶层如不能导出函数内部的函数 也可以整体导出在模块文件的末尾使用一个export语句export { name, draw, reportArea, reportPerimeter }; 2.17.3 导入模块属性 导入import { name, draw, reportArea, reportPerimeter } from ./modules/square.js; 导入的值是导出的特性的只读视图。与const变量类似您不能重新分配已导入的变量但您仍然可以修改对象值的属性 2.17.4 使用导入映射 导入映射是一个JSON对象它允许开发人员在导入JavaScript模块时控制浏览器如何解析模块说明符 使用导入映射必须放在任何 目录结构 /modules/a-old.jsa.js /othermodules/app.js index.html main.js重点总结 1、/test/othermodules/的写法有讲究不能少目录 2、scopes不是scope注意别少s 3、映射文件 a1: ./modules/a.js 4、映射文件夹a1/: ./modules/ script typeimportmap{imports: {a1: ./modules/a.js},scopes: {/test/othermodules/: {a1: ./modules/a-old.js}}} /script !-- main里导入了a1 引用的是a.js-- script typemodule src/test/main.js/script !-- app同样导入了a1但是由于scopes的作用引用的是a-old.js -- script typemodule src/test/othermodules/app.js/script2.17.5 在HTML中应用模块 script typemodule srcmain.js/script注意type的设置 您只能在模块中使用import和export语句而不能在常规脚本中使用。 2.17.6 模块和标准脚本的区别 在本地开发直接打开即使用file:// URL带有模块的html由于JavaScript模块的安全要求你会遇到CORS错误。您需要通过服务器进行测试 报错Access to script at file:///C:/js/main.js from origin null has been blocked by CORS policy: Cross origin requests are only supported for protocol schemes: http, data, isolated-app, chrome-extension, chrome, https, chrome-untrusted.模块自动使用严格模式 在加载模块脚本时不需要使用defer属性 意思就是模块的引入可以在元素之前引用因为自动defer 模块只执行一次即使它们在多个 2.17.7 默认导出 默认导出的作用 使模块提供一个默认的函数更容易有助于CommonJS和AMD之间的交互。 需要把一个函数默认导出使用如下方式 在模块文件的结尾使用export default functionName;注意这里不需要花括号或者在匿名函数前使用export default function (ctx) {} 默认函数的导入不需要花括号 import functionName from ./modules/square.js;注意这里不需要花括号 //module.js export default function(){console.log (默认导出函数执行); }//main.js import fun from ./modules.js; fun();每个模块只允许一个默认导出 如果module没有默认导出函数main中的fun不加花括号就报错 默认导出不能使用常规的导入方式不需要加花括号不需要重命名 2.17.8 重命名导入和导出 在导入和导出的语句中可以使用as后跟新名字去改变名字 导出重命名导入使用新名字 // inside module.js export { function1 as newFunctionName, function2 as anotherNewFunctionName };// inside main.js import { newFunctionName, anotherNewFunctionName } from ./modules/module.js;导出原名称导入重新命名 // inside module.js export { function1, function2 };// inside main.js import {function1 as newFunctionName,function2 as anotherNewFunctionName, } from ./modules/module.js;2.17.9 创建模块对象 上面的方法可以工作但它有点混乱和冗长。一个更好的解决方案是在模块对象中导入所有模块的特性 创建对象Moduleimport * as Module from ./modules/module.js; 这会获取Module .js内部可用的所有导出并使它们作为对象Module的成员可用从而有效地为其提供自己的命名空间 使用创建的对象Module.function1(); 2.17.10 模块中类的导出 正如我们前面所暗示的您还可以导出和导入类;这是避免代码冲突的另一种选择如果您已经以面向对象的风格编写了模块代码则特别有用 模块中的类 class Square {constructor(ctx, listId, length, x, y, color) {// …}draw() {// …} } export { Square };导入类import { Square } from ./modules/square.js; 使用类 const square1 new Square(myCanvas.ctx, myCanvas.listId, 50, 50, 100, blue); square1.draw();2.17.12 聚合模块 其实就是把多个js模块的导出写在一个新的js模块中使用的时候使用新的js模块就可以相当于中转把多个模块聚合到一个模块引用。 示例 //module1.js export function fun1(){console.log (fun1导出函数执行); } //module2.js export function fun2(){console.log (fun2导出函数执行); } //aggregate.js 聚合模块 export {fun1} from ./module1.js; export {fun2} from ./module2.js;//main.js 这样可以使用一个对象module访问多个模块的函数 import * as module from ./aggregate .js; module.fun1(); module.fun2();//html中导入main.js就可以使用2.17.11 动态模块加载 JavaScript模块最近新增的功能是动态模块加载。这允许您仅在需要时动态加载模块而不必预先加载所有内容 允许您将import()作为函数调用并将路径传递给函数。它返回一个Promise它用一个模块对象来实现(参见创建模块对象)让你可以访问该对象的导出 import(./modules/myModule.js).then((module) {// Do something with the module. });动态导入的另一个优点是它们总是可用的即使在脚本环境中也是如此 因此如果你的HTML中有一个现有的 scriptimport(./modules/square.js).then((module) {// Do something with the module.});// Other code that operates on the global scope and is not// ready to be refactored into modules yet.var btn document.querySelector(.square); /script 2.17.12 顶层等待 await只能在默认导出中使用 使用如下方式导出同步的感觉 export default await colors; 2.17.13 导入声明被提升 在这种情况下这意味着导入的值甚至在声明它们的地方之前就可以在模块的代码中使用并且导入的模块的副作用在模块的其余代码开始运行之前就产生了。 尽管如此将所有导入放在代码的顶部被认为是一种良好的实践这使得分析依赖关系变得更加容易 2.17.14 循环导入 // -- a.js -- import { b } from ./b.js;// -- b.js -- import { a } from ./a.js;// Cycle: // a.js ─── b.js // ^ │ // └─────────┘循环导入在异步时是有可能成功的但在同步的情况下肯定报错 通常应该避免在项目中进行循环导入因为这会使代码更容易出错。一些常见的循环消除技术是: 将两个模块合并为一个。将共享代码移动到第三个模块中将一些代码从一个模块移动到另一个模块。 2.17.15 创建“同构”模块 如果模块引用像window这样的全局变量它可以在浏览器中运行但会在Node.js服务器中抛出错误因为那里没有window可用。 类似地如果代码需要访问process才能正常工作那么它只能在Node.js中使用。 三种方式实现代码同构 把你的模块分成“核心”和“绑定”。对于“核心”专注于纯JavaScript逻辑如计算哈希不需要任何DOM、网络、文件系统访问和公开实用程序函数。对于“绑定”部分您可以读取和写入全局上下文在使用特定全局变量之前检测它是否存在。例如如果测试typeof window “undefined”您就知道您可能处于Node.js环境中不应该读取DOMglobalThis变量是一个全局对象在任何环境中都可用如果您希望在模块中读取或创建全局变量它将非常有用 2.17.16 模块排错 “The server responded with a non-JavaScript MIME type”. .mjs文件需要加载一个MIME类型的text/javascript(或其他javascript兼容的MIME类型但推荐text/javascript) CORS错误 如果您尝试在本地加载HTML文件(即使用file:// URL)由于JavaScript模块的安全要求您将遇到CORS错误。您需要通过服务器进行测试 因为.mjs是一个非标准的文件扩展名所以一些操作系统可能无法识别它或者试图用其他东西替换它替换为.mjs.js,然后隐藏扩展名无法发现 三、中级知识 3.1 客户端js框架 JavaScript框架是现代前端web开发的重要组成部分为开发人员提供了久经考验的工具用于构建可伸缩的交互式web应用程序。许多现代公司使用框架作为其工具的标准部分因此许多前端开发工作现在都需要框架经验 问题 我为什么要使用框架?它们为我解决了什么问题?在选择框架时我应该问哪些问题?我甚至需要使用框架吗?框架有哪些特性?它们一般是如何工作的框架对这些特性的实现又有何不同?它们与“普通的”JavaScript或HTML有什么关系? 3.1.1 入门指南 3.1.1.1 介绍客户端框架 有哪些框架 Ember2011年12月发布较老的框架比React和Vue等拥有更少的用户其稳定性、社区支持和一些聪明的编码原则它仍然享有相当大的人气Angular2016年9月14日正式发布。Angular是一个开源的web应用框架由Google的Angular团队以及一个由个人和公司组成的社区领导Vue2014年发布了Vue。和AngularJS一样Vue用自己的代码扩展HTML。除此之外它主要依赖于现代的、标准的JavaScript。React2013年发布了React。从技术上讲React本身并不是一个框架;它是一个渲染UI组件的库 框架为什么存在 在软件开发中这种底层数据被称为state。 每次我们改变应用程序的state时我们都需要更新UI来匹配 JavaScript框架的创建是为了让更新UI工作变得更容易——它们的存在是为了提供更好的开发人员体验。它们不会给JavaScript带来全新的功能;它们让你更容易地访问JavaScript的功能 静态站点生成器 Astro, Eleventy, Hugo, Jekyll, and Gatsby. 3.1.1.2 框架的主要特性 DSLsDomain-Specific Language领域特定语言是为解决特定领域问题而设计的计算机程序语言 JSX代表JavaScript和XML是JavaScript的扩展。它将类似html的语法引入JavaScript环境单花括号HandlebarsHandlebars代码类似于HTML但它可以选择从其他地方拉入数据双花括号TypeScriptTypeScript是JavaScript的超集也就是说它扩展了JavaScript。允许开发人员在代码上强制执行严格性 3.1.2 React教程 3.1.2.1 开始使用React 使用vite来构建应用 为了使用Vite你需要安装Node.js。从Vite 5.0开始至少需要Node版本18或更高版本尽可能运行最新的长期支持(LTS)版本是个好主意 设置第一个app cd到需要的目录根据模板创建项目npm create vitelatest moz-todo-react -- --template react进入目录安装包cd moz-todo-react npm install运行一个本地服务器npm run dev -- --open --port 3000 项目文件结构 moz-todo-react ├── README.md ├── index.html #Vite将代码注入到该文件中以便浏览器可以运行它。在我们的教程中您不需要编辑该文件但是您应该更改该文件中title元素中的文本 ├── node_modules ├── package-lock.json ├── package.json ├── public #公共目录包含静态文件这些文件将直接提供给浏览器而不需要由Vite的构建工具进行处理 │ └── vite.svg ├── src #应用程序的源代码所在 │ ├── App.css │ ├── App.jsx │ ├── assets #包含您在浏览器中看到的React徽标 │ │ └── react.svg │ ├── index.css │ └── main.jsx └── vite.config.js自定义dev脚本 不必在每次运行npm run dev – --open --port 3000时都传递–open和–port标志 更改文件package.json中的scripts对象中的属性dev: vite更改为dev: vite --open --port 3000 这样每次运行npm run dev时你的应用都会在浏览器中打开http://localhost:3000 App.jsx文件 import部分导入相关模块引用css文件App()部分使用大驼峰命名。小驼峰会报错export部分使我们的App()函数对其他模块可用 main.jsx文件 这个文件是我们应用程序的入口点组件在这里使用 3.1.3 Vue教程 3.1.3.1 开始使用Vue 安装 开发脚本script srchttps://unpkg.com/vue3/dist/vue.global.js/script生产脚本script srchttps://unpkg.com/vue3/dist/vue.global.prod.js/script但是在复杂的项目建议使用npm vue包 初始化一个新项目 cd 到需要创建项目的上级目录使用npm create vuelatest创建项目根据提示选择cd 到项目目录安装相应的包npm install启动项目npm run dev 项目文件结构 package.json #该文件包含项目的依赖项列表以及一些元数据和eslint配置 yarn.lock #如果您选择yarn作为包管理器这个文件将生成一个包含项目所需的所有依赖项和子依赖项的列表 jsconfig.json #这是一个用于Visual Studio Code的配置文件它为你的项目结构提供了VS Code的上下文并帮助自动完成 vite.config.js #这是用于在本地机器上构建和服务项目的Vite开发服务器的配置文件。Vite服务器监视源文件的更改并可以在您进行更改时热重新加载项目 public #此目录包含在构建期间发布的静态资产 └── favicon.ico #这是你的应用程序的图标 index.html #Vue应用程序从这个HTML页面运行 src #该目录包含Vue应用程序的核心 ├── main.js #这是入口点。这个文件初始化Vue应用表示应用程序应该附加到index.html文件中的哪个HTML元素。通常是您注册全局组件或附加Vue库的地方 ├── App.vue #这是Vue应用程序中的顶层组件 ├── components #该目录存放组件 └── assets #该目录用于存储CSS和图像等静态资产如果您选择路由器您还将有一个views目录 App.vue文件 template部分包含组件的所有标记结构和显示逻辑script部分包含组件的所有非显示逻辑style部分是为组件编写CSS的地方 3.1.3.2 创建第一个Vue组件 创建一个组件 创建组件创建一个vue文件里面的template标签里写上html导入组件在APP.vue中script标签中用import导入组件注册组件在APP.vue中script标签中导出对象中添加components属性。里面写上导入的组件名使用组件根据导入的组件名的驼峰形式使用时标签名示例组件名AaBbCc则标签名为aa-bb-cc 注册props数据对象 //组件中 export default {//prop,使用{{}}绑定相应数据props: {label: { required: true, type: String },done: { default: false, type: Boolean },},//数据对象使用 :属性名”id“data() {return {isDone: this.done,id: todo- nanoid(),};}, };3.2 客户端web APIs 3.2.1 介绍web APIs 3.2.1.1 什么是APIs 应用程序编程接口(api)是编程语言中可用的结构允许开发人员更容易地创建复杂的功能。 名词解释 JavaScript 一种内置在浏览器中的高级脚本语言允许您在网页/应用程序上实现功能浏览器APIs构建到浏览器中它位于JavaScript语言之上允许您更轻松地实现功能第三方APIs构建到第三方平台(例如Disqus, Facebook)允许您在自己的网页中使用这些平台的一些功能(例如在网页上显示您的Disqus评论)。JavaScript 库通常是一个或多个包含自定义函数的JavaScript文件JavaScript 框架 库和框架的区别 库和框架之间的关键区别在于“控制反转”。当从库中调用方法时开发人员处于控制地位。对于框架控制是颠倒的:框架调用开发人员的代码。 3.2.2 操作文档APIs 3.2.3 从服务器获取数据APIs 3.2.4 第三方APIs 3.2.5 画图APIs 3.2.6 视频和音频APIs 3.2.7 客户端存储APIs 3.3 语言概述 3.4 js数据结构 3.5 相等、比较和相同 3.6 属性的可枚举性和所有权 3.7 闭包 四、高级知识 4.1 继承和原型链 someObject.[[Prototype]]指示对象的原型为内部属性不能直接访问 等价于访问器__proto__为了统一避免使用这种形式 实际访问使用Object.getPrototypeOf() 和Object.setPrototypeOf()函数 函数的 Object.getPrototypeOf(new Box()) Box.prototype 类是构造函数之上的语法糖意味着还可以使用Box.prototype来改变实例的行为 使用函数实现多个原型链: function Base() {} function Derived() {} // Set the [[Prototype]] of Derived.prototype // to Base.prototype Object.setPrototypeOf(Derived.prototype, Base.prototype);const obj new Derived(); // obj --- Derived.prototype --- Base.prototype --- Object.prototype --- null等价于使用类实现 class Base {} class Derived extends Base {}const obj new Derived(); // obj --- Derived.prototype --- Base.prototype --- Object.prototype --- null一个函数在js中默认有 一个prototype属性但是箭头函数没有默认的 function doSomething() {} console.log(doSomething.prototype); const doSomethingFromArrowFunction () {}; console.log(doSomethingFromArrowFunction.prototype);//undefined 4.2 内存管理 4.3 事件循环 五、内置对象 5.1 值属性 这些全局属性返回一个简单的值。它们没有属性或方法 globalThis是一个跨环境的全局对象引用在浏览器端就时windowInfinityInfinity全局属性是一个表示无穷大的数值NaN全局属性是一个表示非数字的值undefined全局属性表示原始值undefined 5.2 函数属性 这些全局函数(全局调用的函数而不是在对象上调用的函数)直接将结果返回给调用者。 eval()表示把字符串当做JavaScript代码执行并返回其完成值。源代码被解析为脚本。isFinite()确定一个值是否为有限值如果需要首先将值转换为数字isNaN()确定一个值是否是NaN如果需要首先将值转换为数字parseFloat()解析字符串参数并返回一个浮点数parseInt()解析字符串参数并返回指定进制的整数。decodeURI()由encodeURI()或类似例程创建的统一资源标识符(URI)进行解码decodeURIComponent()对以前由encodeURIComponent()或类似例程创建的统一资源标识符(URI)组件进行解码encodeURI()通过用表示字符的UTF-8编码的一个、两个、三个或四个转义序列替换特定字符的每个实例来编码URI(对于由两个代理字符组成的字符只有四个转义序列)。与encodeURIComponent()相比该函数编码的字符更少保留了URI语法的一部分。encodeURIComponent()与encodeURI()相比这个函数编码更多的字符包括那些属于URI语法一部分的字符。 5.3 基本对象 这些对象表示基本的语言结构 5.3.1 Object 表示JavaScript的一种数据类型。它用于存储各种键集合和更复杂的实体。 对象可以使用Object()构造函数或对象初始化器/字面量语法创建 5.3.1.1 静态方法 Object.assign() object. assign()静态方法将所有可枚举的自身属性从一个或多个源对象复制到目标对象。它返回修改后的目标对象 如果目标对象中的属性具有相同的键则目标对象中的属性将被源中的属性覆盖。后来的源的属性会覆盖以前的 object. assign()方法只将可枚举和自己的属性从源对象复制到目标对象 原型链上的属性和不可枚举属性不能被复制 //克隆对象浅克隆 const copy Object.assign({}, obj);//如果源值是对对象的引用则它只复制该引用值 //深度克隆 const obj4 structuredClone(obj3); //合并对象 const obj Object.assign(o1, o2, o3);//当对象中有相同属性名时则会覆盖 //原始类型将被包装成对象 const obj Object.assign({}, abc);//字符串’abc‘将被包装成对象{0’a‘1’b‘2’c‘}Object.create() 创建一个新对象使用一个现有对象作为新创建对象的原型 语法 Object.create(proto) Object.create(proto, propertiesObject)Object.defineProperties() 直接在对象上定义新的或修改现有的属性并返回该对象 语法Object.defineProperties(obj, props) Object.defineProperty() 直接在对象上定义新属性或修改对象上的现有属性并返回该对象 语法Object.defineProperty(obj, prop, descriptor) Object.entries() 返回给定对象自己的可枚举字符串键属性键值对的数组 语法Object.entries(obj) 例如{a:2,b:3}返回[[”a“,2],[“b”,3]] Object.freeze() 冻结一个对象冻结对象可以防止扩展并使现有属性不可写和不可配置 Object.fromEntries() 将键值对列表转换为对象。和Object.entries()功能相反 Object.getOwnPropertyDescriptor() 返回一个对象该对象描述给定对象(即直接出现在对象上而不在对象的原型链中)上的特定属性的配置 语法Object.getOwnPropertyDescriptor(obj, prop) Object.getOwnPropertyDescriptors() 返回给定对象的所有自己的属性描述符 语法Object.getOwnPropertyDescriptors(obj) Object.getOwnPropertyNames() 返回直接在给定对象中找到的所有属性(包括非枚举属性除了那些使用Symbol的属性)的数组 语法Object.getOwnPropertyNames(obj) Object.getOwnPropertySymbols() 返回直接在给定对象上找到的所有Symbol属性的数组 语法Object.getOwnPropertySymbols(obj) Object.getPrototypeOf() 返回指定对象的原型(即内部[[prototype]]属性的值) 语法Object.getPrototypeOf(obj) Object.groupBy() 根据所提供的回调函数返回的字符串值对给定可迭代对象的元素进行分组 语法Object.groupBy(items, callbackFn) 返回对象和原始可迭代对象中的元素是相同的(不是深度拷贝)。更改元素的内部结构将反映在原始可迭代对象和返回对象中 Object.hasOwn() 如果指定的对象具有指定的属性作为自己的属性则object . hasown()静态方法返回true。如果属性是继承的或者不存在则该方法返回false。 语法Object.hasOwn(obj, prop) Object.is() 确定两个值是否相同 语法Object.is(value1, value2) Object.isExtensible() 确定对象是否可扩展(是否可以向其添加新属性) 语法Object.isExtensible(obj) Object.isFrozen() 确定对象是否被冻结。 语法Object.isFrozen(obj) Object.isSealed() 确定对象是否被密封。 如果一个对象是不可扩展的并且它的所有属性都是不可配置的因此是不可移动的(但不一定是不可写的)那么这个对象就是密封的。 Object.keys() 返回一个由给定对象自己的可枚举字符串键属性名组成的数组 Object.preventExtensions() 防止新属性被添加到对象中(也就是说防止将来对对象进行扩展)。它还可以防止对象的原型被重新分配 语法Object.preventExtensions(obj) Object.seal() 密封对象 封闭对象可以防止扩展并使现有属性不可配置。密封对象具有一组固定的属性:不能添加新属性不能删除现有属性不能更改其枚举性和可配置性不能重新分配其原型。 只要现有属性的值是可写的它们仍然可以被更改 Object.setPrototypeOf() 指定对象的原型(即内部的[[prototype]]属性)设置为另一个对象或null 语法Object.setPrototypeOf(obj, prototype) Object.values() 返回给定对象自己的可枚举字符串键属性值的数组 5.3.1.2 实例方法 Object.prototype.hasOwnProperty() 返回一个布尔值指示该对象是否具有指定的属性作为其自己的属性(而不是继承它) 在支持Object.hasOwn()的浏览器中建议使用它而不是hasOwnProperty() Object.prototype.isPrototypeOf() 检查这个对象是否存在于另一个对象的原型链中 Object.prototype.propertyIsEnumerable() 返回一个布尔值指示指定的属性是否是该对象的可枚举自身属性。 Object.prototype.toLocaleString() 返回一个表示该对象的字符串。此方法将被派生对象覆盖以实现特定于区域设置的目的 这个方法常用于格式化时间、日期、数值等 Object.prototype.toString() 返回一个表示该对象的字符串。此方法将被用于自定义类型强制转换逻辑的派生对象覆盖 Object.prototype.valueOf() 将this值转换为对象。此方法将被用于自定义类型转换逻辑的派生对象覆盖。 对于基本类型的包装可以使用valueOf还原为基本类型 对象在进行算数运算时会自动调用valueOf 5.3.1.3 实例属性 Object.prototype.constructor 5.3.2 Function 函数提供方法。在JavaScript中每个函数实际上都是一个Function对象 5.3.2.1 构造方法 new Function(functionBody) new Function(arg1, functionBody)5.3.2.2 实例方法 Function.prototype.apply() 使用给定的this值和作为数组(或类似数组的对象)提供的参数调用此函数 语法apply(thisArg, argsArray) 示例 function fun(x,y){//fun.apply(obj1,[2,4])//this为obj1数组中的参数传递给函数console.log (this.e x y); }const obj1 {e:123} const obj2 {e:1234}fun.apply(obj1,[2,4]) fun.apply(obj2,[5,9])Function.prototype.bind() 创建一个新函数当调用该函数时将this关键字设置为提供的值并在调用新函数时提供的任何参数之前提供给定的参数序列 语法bind(thisArg, arg1, arg2) 示例 function fun(x,y){console.log (this.exy); } const obj1 {e:1} const fun2 fun.bind(obj1,2,4)//返回函数不会立即执行 fun2();Function.prototype.call() 使用给定的this值和单独提供的参数调用此函数 语法call(thisArg, arg1, arg2) 示例 function fun(x,y){console.log (this.exy); } const obj1 {e:1} fun.call(obj1,2,4)//和bind一样只不过函数直接执行了Function.prototype.toString() 返回一个表示此函数源代码的字符串 Function.prototype[hasInstance]() 确定一个对象是否是构造函数的实例 hasInstance等价于Symbol.hasInstance function fun(x,y){console.log (xy); } const ob new fun(2,3) const s fun[Symbol.hasInstance](ob)//等价于ob instanceof fun console.log (s);//true5.3.2.3 实例属性 length 指示函数期望的参数数量。 name 表示创建时指定的函数名对于匿名创建的函数它可以是anonymous或(一个空字符串) prototype 当函数作为带有new操作符的构造函数使用时使用Function实例的prototype data属性。它将成为新对象的原型 5.3.3 Boolean 布尔对象表示一个真值:true或false。 若要将非布尔值转换为布尔值请使用boolean作为函数或使用双NOT操作符。不要对new使用Boolean()构造函数。 因为new出来的不管是true还是false布尔对象在条件语句中就是true const bad new Boolean(21)console.log (bad);//Boolean {false} if(bad){console.log (---------);//实际会输出 }布尔强制转换 undefined转换为 false.null转换为false.0, -0, 和 NaN 转换为 false; 其他数值转换为 true.0n 转换为 false; 其他BigInts转换为true.转换为false; 其他字符串转换为 true.Symbols转换为 true.所有对象转换为true. 5.3.4 Symbol 新增的基本数据类型 Symbol通常用于向对象添加唯一属性键这些键不会与任何其他代码可能添加到对象的键发生冲突并且隐藏于其他代码通常用于访问对象的任何机制之外。 每次Symbol.for(“key”)调用都会为给定的key值返回相同的Symbol 当Symbol.for(“key”)被调用时如果在全局Symbol注册表中可以找到具有给定键的Symbol则返回该Symbol。否则将创建一个新的Symbol将其添加到给定键下的全局Symbol注册表中并返回。 方法Symbol.for(tokenString)接受一个字符串键并从注册表返回一个符号值 而Symbol. keyfor(symbolValue)接受一个符号值并返回与之对应的字符串键。每一个都是另一个的倒数 5.4 错误对象 错误对象是基本对象的一种特殊类型。它们包括基本的错误类型以及一些专门的错误类型 错误的类型 AggregateError 当需要将多个错误包装在一个错误中时AggregateError对象表示错误 try {throw new AggregateError([new Error(some error),new Error(some error222)], Hello); } catch (e) {console.log(e instanceof AggregateError); // trueconsole.log(e.message); // Helloconsole.log(e.name); // AggregateErrorconsole.log(e.errors); // [ Error: some error ] }EvalError 表示关于全局eval()函数的错误 try {throw new EvalError(Hello); } catch (e) {console.log(e instanceof EvalError); // trueconsole.log(e.message); // Helloconsole.log(e.name); // EvalErrorconsole.log(e.stack); // Stack of the error }RangeError 当一个值不在允许的值的集合或范围中时出现错误 ReferenceError 表示在引用当前作用域中不存在(或尚未初始化)的变量时发生错误。 SyntaxError 表示在尝试解释语法上无效的代码时发生错误。当JavaScript引擎在解析代码时遇到不符合语言语法的令牌或令牌顺序时就会抛出 TypeError 表示无法执行操作时的错误通常(但不限于)当值不是预期类型时 URIError 当以错误的方式使用全局URI处理函数时 5.5 数值和日期 这些是表示数字、日期和数学计算的基本对象。 5.5.1 Number 5.5.1.1 静态属性 Number.EPSILON 它定义了 JavaScript 中能表示的最小正数也就是说它是 JavaScript 可以区分的两个浮点数之间的最小差值 浮点数永远都不要使用比较大小 在进行浮点数比较时Number.EPSILON 可用来设定一个误差范围以避免因浮点数精度问题导致的比较不准确。 Number.MAX_SAFE_INTEGER 表示JavaScript中的最大安全整数 Number.MAX_VALUE 表示JavaScript中可表示的最大数值 Number.MIN_SAFE_INTEGER 表示JavaScript中的最小安全整数 Number.MIN_VALUE 表示JavaScript中可表示的最小数值 Number.NaN 表示不是一个数值 Number.NEGATIVE_INFINITY 表示负无穷大值 Number.POSITIVE_INFINITY 表示正无穷大的值 5.5.1.2 静态方法 Number.isFinite() 它检查给定的值是否是一个数字并且这个数字既不是正无穷大也不是负无穷大也不是NaN。 Number.isInteger() 确定传递的值是否是整数。 Number.isNaN() 定传递的值是否是数值NaN Number.isSafeInteger() 定所提供的值是否是一个安全整数 Number.parseFloat() 解析一个参数并返回一个浮点数。如果不能从参数中解析出一个数字则返回NaN Number.parseInt() 解析一个参数并返回一个整数数。如果不能从参数中解析出一个数字则返回NaN 5.5.1.3 实例方法 Number.prototype.toExponential() 返回一个以指数表示法表示该数字的字符串 Number.prototype.toFixed() 用于将数字格式化为指定小数位数的字符串会进行四舍五入 关注的是小数的位数 Number.prototype.toLocaleString() Number.prototype.toPrecision() 返回一个表示该数字的指定精度的字符串 关注的是整体的位数 Number.prototype.toString() Number.prototype.valueOf() 5.5.2 BigInt 是一个大数通过在整数字面值的末尾添加n或通过调用BigInt()函数(不带new操作符)并给它一个整数值或字符串值来创建 5.5.2.1 静态方法 BigInt.asIntN() 将一个BigInt值压缩为一个带符号整数值并返回该值 BigInt.asUintN() 将一个BigInt值压缩为一个无符号整型值并返回该值 5.5.2.2 实例方法 BigInt.prototype.toLocaleString()BigInt.prototype.toString()BigInt.prototype.valueOf() 5.5.3 Math 5.5.4 Date 5.6 文本处理 这些对象表示字符串并支持对它们进行操作。 5.6.1 String 5.6.1.1 静态方法 String.fromCharCode() 返回一个由指定的UTF-16编码单元序列创建的字符串。 参数为0到65535之间的数字(0xFFFF)表示UTF-16编码单元 String.fromCodePoint() 返回一个由指定代码点序列创建的字符串。 参数为一个介于0和0x10FFFF(包括)之间的整数表示Unicode码点 String.raw() 用于获取一个模板字符串的原始字符串形式。 5.6.1.2 实例方法 String.prototype[iterator]() 它返回一个字符串迭代器对象该对象以单个字符串的形式生成字符串值的Unicode码点 const iterator 这是一个字符串[Symbol.iterator](); while(!(temp iterator.next()).done){console.log (temp.value); }String.prototype.at() 接受一个整数值并返回一个由位于指定偏移量的单个UTF-16代码单元组成的新String。这个方法允许正整数和负整数。 负整数从最后一个字符串字符开始倒数。 超出索引返回undefined String.prototype.charAt() 接受一个正整数值并返回一个由位于指定偏移量的单个UTF-16代码单元组成的新String。这个方法允许正整数 超出索引返回 String.prototype.charCodeAt() 字符串值的charCodeAt()方法返回一个介于0到65535之间的整数表示给定索引处的UTF-16代码单元 String.prototype.codePointAt() 返回一个非负整数即从给定索引开始的字符的Unicode码点值 String.prototype.concat() 将字符串参数连接到此字符串并返回一个新字符串 console.log(str2.concat(, , str1)); String.prototype.endsWith() 确定字符串是否以该字符串的字符结束并根据需要返回true或false endsWith(searchString, endPosition) String.prototype.includes() 执行区分大小写的搜索以确定给定字符串是否可以在此字符串中找到并根据情况返回true或false String.prototype.indexOf() 搜索此字符串并返回指定子字符串第一次出现的索引 String.prototype.isWellFormed() 返回一个布尔值指示该字符串是否包含任何lone surrogates 字符在0xD800-0xDFFF范围的为lone surrogates String.prototype.lastIndexOf() 搜索该字符串并返回指定子字符串最后出现的索引。它接受一个可选的起始位置并返回指定子字符串在小于或等于指定数字的索引处的最后一次出现 String.prototype.localeCompare() 比较两个字符串的前后 String.prototype.match() 正则表达式匹配返回匹配结果为数组 String.prototype.matchAll() 返回一个迭代器其中包含与正则表达式匹配的字符串的所有结果包括捕获组。 String.prototype.normalize() 返回该字符串的Unicode规范化形式。 //有些字符可以有两个表示形式第一种直接单个字符第二种为n~两个字符来表示 const string1 \u00F1; // ñ const string2 \u006E\u0303; // ñconsole.log(string1 string2); // false console.log(string1.length); // 1 console.log(string2.length); // 2string1 string1.normalize(NFD);//在这种形式中组合字符序列被拆分为基本字符和单独的组合重音符号 string2 string2.normalize(NFD); console.log(string1 string2); // true console.log(string1.length); // 2 console.log(string2.length); // 2string1 string1.normalize(NFC);//在这种形式中组合字符序列被最大限度地转换为单个字符 string2 string2.normalize(NFC); console.log(string1 string2); // true console.log(string1.length); // 1 console.log(string2.length); // 1String.prototype.padEnd() 在末尾使用给定的字符串填充字符串到给定的长度 语法padEnd(填充到的总长度, 填充字符) String.prototype.padStart() 在开始使用给定的字符串填充字符串到给定的长度 语法padEnd(填充到的总长度, 填充字符) String.prototype.repeat() 构造并返回一个新字符串其中包含该字符串的指定数量的连接在一起的副本 String.prototype.replace() 字符串替换使用replacement替换pattern pattern字符串或正则 replacement字符串或函数 语法replace(pattern, replacement) String.prototype.replaceAll() 可以替换多个 String.prototype.search() 执行正则表达式与该字符串之间的匹配搜索返回字符串中第一个匹配的索引。 String.prototype.slice() 提取该字符串的一部分并将其作为新字符串返回而不修改原始字符串。 String.prototype.split() 接受一个模式并通过搜索该模式将该字符串划分为有序的子字符串列表将这些子字符串放入数组并返回该数组。 String.prototype.startsWith() 定该字符串是否以指定字符串的字符开头并根据需要返回true或false。 String.prototype.substring() 返回从开始索引到不包括结束索引的字符串部分如果没有提供结束索引则返回到字符串的末尾。 String.prototype.toLocaleLowerCase() 返回根据任何特定于语言环境的大小写映射转换为小写的字符串。 String.prototype.toLocaleUpperCase() 根据任何特定于语言环境的大小写映射返回转换为大写的字符串。 String.prototype.toLowerCase() 返回转换为小写的字符串。 String.prototype.toString() 返回字符串对象的字符串值 String.prototype.toUpperCase() 返回转换为大写的字符串。 String.prototype.toWellFormed() 回一个字符串其中该字符串的所有单独代理都被Unicode替换字符UFFFD替换。 String.prototype.trim() 从字符串的两端删除空白并返回一个新字符串而不修改原始字符串。 String.prototype.trimEnd() 字符串末尾删除空白并返回一个新字符串而不修改原始字符串 String.prototype.trimStart() 字符串值的trimStart()方法从字符串的开头删除空白并返回一个新字符串而不修改原始字符串 String.prototype.valueOf() 返回这个字符串值。 对象类型转换为基本类型 5.6.1.3 实例属性 String: length 字符串值的length data属性以UTF-16编码单位表示字符串的长度 5.6.2 RegExp 正则表达式创建方式 const re /abc/i; // literal notation const re new RegExp(abc, i); // constructor with string pattern as first argument const re new RegExp(/abc/, i); // constructor with regular expression literal as first argument在使用正则表达式之前必须对它们进行编译 正则表达式的flag就是上面代码的i位置处的字符也可能是其他字符 5.6.2.1 实例属性 RegExp.prototype.dotAll 返回该正则表达式是否使用s标志。s标志允许.匹配换行符。 RegExp.prototype.flags 返回这个正则表达式的标志。 RegExp.prototype.global 返回是否将g标志用于此正则表达式。g标志全局搜索 RegExp.prototype.hasIndices 返回d标志是否与此正则表达式一起使用。d标志为子字符串匹配生成索引 RegExp.prototype.ignoreCase 返回i标志是否与此正则表达式一起使用。i标志不区分大小写的搜索 RegExp: lastIndex 指定开始下一次匹配的索引。 RegExp.prototype.multiline 返回m标志是否用于此正则表达式。m标志允许^和$在换行符旁边匹配。 RegExp.prototype.source 返回一个字符串其中包含正则表达式的源文本没有两边的两个正斜杠或任何标志。 RegExp.prototype.sticky 返回该正则表达式是否使用了y标志。 RegExp.prototype.unicodey标志执行从目标字符串的当前位置开始匹配的“粘性”搜索 返回该正则表达式是否使用u标志。u标志将模式视为Unicode码点序列 RegExp.prototype.unicodeSets 回该正则表达式是否使用v标志。v标志升级到具有更多Unicode功能的u模式。 5.6.2.2 实例方法 RegExp.prototype.exec() 使用此正则表达式执行搜索以查找指定字符串中的匹配项并返回结果数组或null。 返回一个数组并更新正则表达式对象的lastIndex属性。返回的数组将匹配的文本作为第一项然后为匹配文本的每个捕获组提供一项并且还有其他项 RegExp.prototype.test() 使用此正则表达式执行搜索以查找正则表达式与指定字符串之间的匹配。如果有匹配返回true;否则错误。 RegExp.prototype.toString() 返回一个表示该正则表达式的字符串 5.7 索引集合 这些对象表示按索引值排序的数据集合。这包括(类型化)数组和类数组结构。 5.7.1 Array 5.7.1.1 静态方法 Array.from() 从一个可迭代对象或类数组对象创建一个新的、浅复制的Array实例。 console.log(Array.from([1, 2, 3], function(element,index){console.log (element,index);return element }));array. from()从不创建稀疏数组。如果arrayLike对象缺少一些索引属性则它们在新数组中变为未定义。 Array.fromAsync() 从异步可迭代对象、可迭代对象或类数组对象创建一个新的、浅复制的Array实例。 Array.isArray() 确定传递的值是否是Array。 Array.of() 从可变数量的参数创建一个新的Array实例而不考虑参数的数量或类型。 5.7.1.2 实例方法 Array.prototype.at() 接受一个整数值并返回该索引处的项允许正整数和负整数。负整数从数组中的最后一项开始计数 语法at(index) Array.prototype.concat() 用于合并两个或多个数组。此方法不会更改现有数组而是返回一个新数组。 语法concat(value1,..., value2) Array.prototype.copyWithin() 将此数组的一部分浅层复制到同一数组中的另一个位置并返回该数组而不修改其长度。 语法copyWithin(target, start, end)//将start到end位置的值复制到target位置 Array.prototype.entries() 返回一个新的数组迭代器对象其中包含数组中每个索引的键/值对。 语法entries() Array.prototype.every(fun) 测试数组中的所有元素是否通过所提供的函数实现的测试。它返回一个布尔值 通俗将数组种的每一项传递到函数中返回值全是true时every()返回true 语法every(callbackFn)every(callbackFn, thisArg) Array.prototype.fill() 将数组中索引范围内的所有元素更改为静态值。它返回修改后的数组。 通俗就是填充数组 语法fill(value)fill(value, start)fill(value, start, end) Array.prototype.filter() 创建给定数组部分的浅拷贝过滤后只保留给定数组中通过所提供函数实现的测试的元素。 通俗就是根据回调函数过滤数组元素返回新数组 语法filter(callbackFn)filter(callbackFn, thisArg) 回调函数三个参数 element每个元素index元素索引array原始数组 Array.prototype.find() 返回所提供的数组中满足所提供的测试函数的第一个元素。如果没有值满足测试函数则返回undefined。 注意只是找到第一个满足回调函数的元素就停止了 语法find(callbackFn)find(callbackFn, thisArg) Array.prototype.findIndex() 返回满足所提供的测试函数的数组中第一个元素的索引。如果没有元素满足测试函数则返回-1。 和find类似只是这个返回索引 Array.prototype.findLast() 以相反的顺序迭代数组并返回满足所提供的测试函数的第一个元素的值。如果没有元素满足测试函数则返回undefined。 和find类似只是从末尾开始查找 Array.prototype.findLastIndex() 以相反的顺序迭代数组并返回满足所提供的测试函数的第一个元素的索引。如果没有元素满足测试函数则返回-1。 和find类似只是这个从末尾开始返回索引 Array.prototype.flat() 创建一个新数组其中所有子数组元素递归地连接到其中直至指定的深度。 通俗就是把一个数组种的子数组展开展开的深度由参数决定 语法flat(depth) Array.prototype.flatMap() 返回一个新数组该数组通过对数组的每个元素应用给定的回调函数形成然后将结果平面化一级。 相当于应用map之后再flat Array.prototype.forEach() 对每个数组元素执行一次所提供的函数。 语法forEach(callbackFn)forEach(callbackFn, thisArg) Array.prototype.includes() 确定数组是否在其条目中包含某个值并根据需要返回true或false。 Array.prototype.indexOf() 返回在数组中可以找到给定元素的第一个索引如果该元素不存在则返回-1。 Array.prototype.join() 通过连接该数组中的所有元素(用逗号或指定的分隔符字符串分隔)来创建并返回一个新字符串。如果数组只有一个项则返回该项而不使用分隔符 Array.prototype.keys() 返回一个新的数组迭代器对象其中包含数组中每个索引的键。 Array.prototype.lastIndexOf() 返回在数组中可以找到给定元素的最后一个索引如果不存在则返回-1。从fromIndex开始向后搜索数组。 Array.prototype.map() 创建一个新数组其中填充对调用数组中的每个元素调用所提供函数的结果。 Array.prototype.pop() 数组中删除最后一个元素并返回该元素。这个方法改变数组的长度。 Array.prototype.push() 将指定的元素添加到数组的末尾并返回数组的新长度 Array.prototype.reduce() 按顺序对数组的每个元素执行用户提供的“reducer”回调函数传递对前一个元素计算的返回值。在数组的所有元素上运行reducer的最终结果是一个单一的值。 做数组元素的累加比较合适 Array.prototype.reduceRight() 对累加器和数组的每个值(从右到左)应用一个函数以将其减少为单个值。 Array.prototype.reverse() 将数组就地反转并返回对同一数组的引用 Array.prototype.shift() 从数组中移除第一个元素并返回被移除的元素。这个方法改变数组的长度。 Array.prototype.slice() 将数组的一部分的浅拷贝返回到从开始到结束(不包括结束)选择的新数组对象中其中start和end表示该数组中项的索引。原数组不能被修改 Array.prototype.some() 测试数组中是否至少有一个元素通过所提供的函数实现的测试。如果在数组中找到所提供函数为其返回true的元素则返回true;否则返回false。它不会修改数组。 some和every的区别some要求只有一个满足才返回true。every要求全部满足才返回true Array.prototype.sort() 对数组的元素进行排序并返回对已排序的同一数组的引用 Array.prototype.splice() 通过删除或替换现有元素和/或添加新元素来更改数组的内容 语法splice(start, deleteCount, item1, item2) 对原数组进行了更改返回切下来的数组 Array.prototype.toLocaleString() 返回一个表示数组元素的字符串 Array.prototype.toReversed() 是reverse()方法的复制副本。它返回一个元素顺序颠倒的新数组。 返回新数组不改变元素组 reverse()会改变原数组 Array.prototype.toSorted() 是sort()方法的复制版本。它返回一个元素按升序排序的新数组。 Array.prototype.toSpliced() 是splice()方法的复制版本。它返回一个新数组其中在给定索引处删除和/或替换了一些元素 Array.prototype.toString() 返回一个表示指定数组及其元素的字符串。 Array.prototype.unshift() 将指定的元素添加到数组的开头并返回数组的新长度。 Array.prototype.values() 返回一个新的数组迭代器对象该对象迭代数组中每个项的值。 Array.prototype.with() 使用括号符号改变给定索引值的复制版本。它返回一个新数组其中给定索引处的元素被给定值替换 5.7.2 TypedArray typearray对象描述了底层二进制数据缓冲区的类似数组的视图 5.7.2.1 静态方法 TypedArray.from() 从一个类数组或可迭代对象创建一个新的类型化数组 TypedArray.of() 根据可变数量的参数创建一个新的类型化数组 5.7.2.2 实例属性 TypedArray.prototype.buffer 返回该类型数组所引用的ArrayBuffer或SharedArrayBuffer。 TypedArray.prototype.byteLength 返回该类型数组的长度(以字节为单位)。 TypedArray.prototype.byteOffset 返回该类型数组从其ArrayBuffer或SharedArrayBuffer开始的偏移量(以字节为单位)。 TypedArray.prototype.length 返回这个类型化数组的长度(以元素为单位)。 5.7.5.3 构造语法 new Uint8Array() new Uint8Array(length) new Uint8Array(typedArray) new Uint8Array(object)new Uint8Array(buffer) new Uint8Array(buffer, byteOffset) new Uint8Array(buffer, byteOffset, length)TypeValue RangeSize in bytes备注Int8Array-128 to 1271Uint8Array0 to 2551当元素超出255时溢出Uint8ClampedArray0 to 2551当元素超出255时只显示255Int16Array-32768 to 327672Uint16Array0 to 655352Int32Array-2147483648 to 21474836474Uint32Array0 to 42949672954Float16Array-65504 to 655042Float32Array-3.4e38 to 3.4e384Float64Array-1.8e308 to 1.8e3088BigInt64Array-263 to 263 - 18BigUint64Array0 to 264 - 18 5.8 键集合 这些对象表示使用键的集合。可迭代集合(Map和Set)包含易于按插入顺序迭代的元素。 5.8.1 Map 5.8.1.1 静态方法 Map.groupBy() 使用提供的回调函数返回的值对给定可迭代对象的元素进行分组。最后返回的Map使用来自test函数的唯一值作为键可用于获取每个组中的元素数组。 该方法主要用于对与对象相关联的元素进行分组特别是当该对象可能随时间变化时。如果对象是不变的则可以使用字符串表示它并使用object . groupby()对元素进行分组。 5.8.1.2 实例方法 Map.prototype[iterator]() 返回可迭代对象 const iterator1 map1[Symbol.iterator](); Map.prototype.clear() 从该映射中删除所有元素。 Map.prototype.delete() 按键从该映射中删除指定的元素。 Map.prototype.entries() 返回一个新的映射迭代器对象该对象按插入顺序包含此映射中每个元素的[key, value]对。 Map.prototype.forEach() 对该映射中的每个键/值对按插入顺序执行一次所提供的函数。 Map.prototype.get() 从这个映射返回指定的元素。 如果与提供的键相关联的值是一个对象那么您将获得对该对象的引用对该对象所做的任何更改都将有效地在Map对象中修改它。 Map.prototype.has() 返回一个布尔值指示具有指定键的元素是否存在于此映射中 Map.prototype.keys() 返回一个新的映射迭代器对象该对象按插入顺序包含此映射中每个元素的键。 Map.prototype.set() 使用指定的键和值在该映射中添加或更新一个条目。 Map.prototype.values() 返回一个新的映射迭代器对象该对象按插入顺序包含该映射中每个元素的值。 5.8.1.3 实例属性 Map.prototype.size 返回该映射中元素的数量。 5.8.2 Set 5.8.2.1 实例方法 Set.prototype[iterator]() 它返回一个集合迭代器对象该对象按插入顺序生成该集合的值。 Set.prototype.add() 将一个具有指定值的新元素插入到这个集合中如果这个集合中没有具有相同值的元素 Set.prototype.clear() 从这个集合中删除所有元素。 Set.prototype.delete() 从这个集合中删除指定的值如果它在集合中。 Set.prototype.difference() 接受一个集合并返回一个新集合其中包含该集合中的元素但不在给定集合中。 A.difference(B)在A里但不在B里 Set.prototype.entries() 返回一个新的Set迭代器对象该对象包含该集合中每个元素的[value, value]数组按插入顺序排列 对于Set对象没有像Map对象那样的键。但是为了使API类似于Map对象每个条目在这里的键和值都具有相同的值 因此返回一个数组[value, value]。 Set.prototype.forEach() 按插入顺序对该集合中的每个值执行一次所提供的函数 Set.prototype.has() 返回一个布尔值指示具有指定值的元素是否存在于此集合中 Set.prototype.intersection() 接受一个集合并返回一个包含该集合和给定集合元素的新集合。 A.intersection(B)在A里也在B里 Set.prototype.isDisjointFrom() 接受一个集合并返回一个布尔值指示该集合是否没有与给定集合相同的元素。 是否有交集 Set.prototype.isSubsetOf() 接受一个集合并返回一个布尔值表示该集合的所有元素是否都在给定集合中。 A.isSubsetOf(B)A是否是B的子集 Set.prototype.isSupersetOf() 接受一个集合并返回一个布尔值表示给定集合的所有元素是否都在这个集合中。 A.isSupersetOf(B)A是否是B的父集 Set.prototype.keys() 是values()方法的别名。 Set.prototype.symmetricDifference() 接受一个集合并返回一个新集合其中的元素要么在这个集合中要么在给定的集合中但不同时在这两个集合中。 A.symmetricDifference(B)在A不在B在B不在A Set.prototype.union() 接受一个集合并返回一个新集合其中包含在该集合和给定集合中的一个或两个元素。 A.union(B)A和B合并 Set.prototype.values() 返回一个新的Set迭代器对象该对象按插入顺序包含该集合中每个元素的值。 5.8.2.2 实例属性 Set.prototype.size 返回这个集合中(唯一的)元素的个数 5.8.3 WeakMap Map 和 WeakMap 都是 JavaScript 中用于存储键值对的数据结构但它们之间存在一些重要的差异。 键的类型 在 Map 中键可以是任何类型包括对象、函数、基本类型等。而在 WeakMap 中键必须是对象。引用关系 在 Map 中一旦设置了键值对即使你删除了对键的所有引用这个键值对也会在 Map 中保留。但在 WeakMap 中如果你删除了对键的所有引用这个键值对会被自动从 WeakMap 中删除。这是因为 WeakMap 对键持有的是弱引用。遍历和大小 Map 有 .size 属性和 .keys(), .values(), .entries() 等方法你可以使用这些方法获取 Map 的大小和遍历 Map。但 WeakMap 没有这些属性和方法你不能获取 WeakMap 的大小或遍历 WeakMap。使用场景 由于 WeakMap 的这些特性它通常用于在不影响垃圾回收的情况下向对象添加额外的信息。而 Map 更常见它可以用于存储各种类型的键值对并且可以方便地遍历它们。 总的来说虽然 Map 和 WeakMap 在某些方面相似但由于它们的这些差异它们在 JavaScript 中的应用场景是不同的。 5.8.4 WeakSet Set 和 WeakSet 都是 JavaScript 中用于存储唯一值的数据结构但它们有一些重要的区别 元素类型 在 Set 中你可以添加任何类型的元素包括原始类型如数字和字符串和对象类型。而在 WeakSet 中你只能添加对象。对元素的引用 Set 对其元素持有的是强引用这意味着只要 Set 存在它的元素就不会被垃圾回收机制回收。而 WeakSet 对其元素持有的是弱引用如果没有其他地方引用 WeakSet 中的对象这些对象就会被垃圾回收机制回收。遍历和大小 Set 有 .size 属性和 .values(), .keys(), .entries() 等方法可以用来获取 Set 的大小和遍历 Set。但 WeakSet 没有这些属性和方法你不能获取 WeakSet 的大小或遍历 WeakSet。使用场景 由于 WeakSet 的特性它通常用于在不影响垃圾回收的情况下向对象添加一些额外的信息。而 Set 更多的是用来存储和操作一组不重复的元素。 总之Set 和 WeakSet 都有各自的特点和使用场景需要根据具体需求来选择使用哪一个。 5.9 结构化数据 这些对象表示结构化数据缓冲区和使用JavaScript对象表示法(JSON)编码的数据并与之交互。 5.9.1 ArrayBuffer ArrayBuffer对象用于表示一个通用的原始二进制数据缓冲区 它是一个字节数组在其他语言中通常称为“字节数组”。你不能直接操作ArrayBuffer的内容;相反您可以创建一个类型化数组对象或以特定格式表示缓冲区的DataView对象并使用它来读写缓冲区的内容。 5.9.1.1 静态方法 ArrayBuffer.isView() 确定传递的值是否是ArrayBuffer视图中的一个例如类型化数组对象或DataView。 5.9.1.2 实例方法 ArrayBuffer.prototype.resize() 将ArrayBuffer的大小调整到指定的大小(以字节为单位)。 ArrayBuffer.prototype.slice() 返回一个新的ArrayBuffer它的内容是这个ArrayBuffer的字节拷贝从开始包括到结束不包括。如果start或end为负值则指向数组末尾的索引而不是从头开始的索引 ArrayBuffer.prototype.transfer() 创建一个新的ArrayBuffer其字节内容与这个缓冲区相同然后分离这个缓冲区。 ArrayBuffer.prototype.transferToFixedLength() 创建一个新的不可调整大小的ArrayBuffer其字节内容与此缓冲区相同然后分离此缓冲区。 5.9.1.3 实例属性 ArrayBuffer.prototype.byteLength 返回该数组缓冲区的长度(以字节为单位)。 ArrayBuffer.prototype.detached 返回一个布尔值表示该缓冲区是否已被分离(传输)。 ArrayBuffer.prototype.maxByteLength 属性返回该数组缓冲区可以调整到的最大长度(以字节为单位)。 ArrayBuffer.prototype.resizable 返回该数组缓冲区是否可以调整大小。 创建时设置了 maxByteLength比byteLength长才可以调整缓冲区 5.9.2 SharedArrayBuffer 用来表示一个通用的原始二进制数据缓冲区类似于ArrayBuffer对象但在某种程度上它们可以用来在共享内存上创建视图 SharedArrayBuffer不是一个可转移对象不像ArrayBuffer是可转移的 5.9.2.1 实例方法 SharedArrayBuffer.prototype.grow() 将SharedArrayBuffer增加到指定的大小(以字节为单位)。 SharedArrayBuffer.prototype.slice() 返回一个新的SharedArrayBuffer它的内容是这个SharedArrayBuffer的字节拷贝从开始包括到结束不包括。如果start或end为负值则指向数组末尾的索引而不是从头开始的索引。 5.9.2.3 实例属性 SharedArrayBuffer.prototype.byteLength 返回这个SharedArrayBuffer的长度(以字节为单位)。 SharedArrayBuffer.prototype.growable 返回这个SharedArrayBuffer是否可以增长。 SharedArrayBuffer.prototype.maxByteLength 返回这个SharedArrayBuffer可以增长到的最大长度(以字节为单位)。 5.9.3 DataView 提供了一个低级接口用于读写二进制ArrayBuffer中的多个数字类型而不必关心平台的端序高字节或低字节在前的问题 new DataView(buffer, byteOffset, byteLength) 在JavaScript中DataView和TypedArray都是用来操作二进制数据的接口它们各有特点适用于不同的场景。 DataView提供了一个更灵活的接口来读取和写入多种数字类型可以自由设定字节序。如果你需要处理不同类型的数据或者需要在大端和小端字节序之间进行切换DataView可能是更好的选择。TypedArray提供了一种在ArrayBuffer对象上读写特定数据类型的机制。它比DataView更快因为数据始终保持相同的字节序并且可以直接作为普通数组使用。如果你在处理大量的同一类型数据或者不需要关心字节序那么TypedArray可能更适合。 所以选择使用DataView还是TypedArray主要取决于你的具体需求。 //内存开辟一段空间 const buffer new ArrayBuffer(8);// 根据该空间创建一个DataView const view1 new DataView(buffer); // 根据该空间创建一个DataView该DataView从buffer的第二个字节开始往后4个字节的区域 const view2 new DataView(buffer, 2, 4); view1.setInt8(2, 42); // 把42放在该段空间的第二个位置console.log(view1); console.log(view2);5.9.4 Atomics 它是一种用于执行原子操作的静态方法集合常常用在多线程编程中以确保多个线程对共享内存区进行操作时的数据完整性。 5.9.4.1 静态方法 Atomics.add() 在数组中的给定位置加上给定值并返回该位置的旧值。这个原子操作保证在修改后的值被写回之前不会发生其他写操作。 语法Atomics.add(typedArray, index, value) Atomics.and() 对数组中给定位置的给定值进行位与运算并返回该位置的旧值。这个原子操作保证在修改后的值被写回之前不会发生其他写操作。 语法Atomics.and(typedArray, index, value) Atomics.compareExchange() 在数组中给定位置交换给定的替换值如果给定的期望值等于旧值。它返回该位置的旧值无论它是否等于期望值。这个原子操作保证在修改后的值被写回之前不会发生其他写操作 语法Atomics.compareExchange(typedArray, index, expectedValue, replacementValue) Atomics.exchange() 交换数组中给定位置的给定值并返回该位置的旧值。这个原子操作保证在读取旧值和写入新值之间不会发生其他写操作。 语法Atomics.exchange(typedArray, index, value) Atomics.isLockFree() 用于确定Atomics方法在应用于具有给定元素字节大小的类型化数组时是使用锁还是原子硬件操作。如果给定的大小不是整型typearray类型的BYTES_PER_ELEMENT属性之一则返回false。 Atomics.load() 返回数组中给定位置的值。 语法Atomics.load(typedArray, index) Atomics.notify() 通知在等待队列中休眠的一些代理。 语法Atomics.notify(typedArray, index, count) Atomics.or() 使用数组中给定位置上的给定值计算位或并返回该位置上的旧值。这个原子操作保证在修改后的值被写回之前不会发生其他写操作。 语法Atomics.or(typedArray, index, value) Atomics.store() 将给定值存储在数组中的给定位置并返回该值。 语法Atomics.store(typedArray, index, value) Atomics.sub() 减去数组中给定位置的给定值并返回该位置的旧值。这个原子操作保证在修改后的值被写回之前不会发生其他写操作。 语法Atomics.sub(typedArray, index, value) Atomics.wait() 验证共享内存位置是否仍然包含给定值如果是则休眠等待唤醒通知或超时。它返回一个字符串要么是“ok”要么是“not-equal”要么是“timeout”。 Atomics.waitAsync() 在共享内存位置异步等待并返回一个Promise 与Atomics.wait()不同waitAsync是非阻塞的并且可以在主线程上使用。 Atomics.xor() 使用数组中给定位置上的给定值计算位异或并返回该位置上的旧值。这个原子操作保证在修改后的值被写回之前不会发生其他写操作。 5.9.5 JSON 5.9.5.1 静态方法 JSON.parse() 解析JSON字符串构造由字符串描述的JavaScript值或对象。可以提供一个可选的reviver函数用于在返回结果对象之前对其执行转换。 语法JSON.parse(text)JSON.parse(text, reviver) JSON.stringify() 将JavaScript值转换为JSON字符串如果指定了替换函数则可选地替换值;如果指定了替换数组则可选地只包含指定的属性。 JSON.stringify(value) JSON.stringify(value, replacer) JSON.stringify(value, replacer, space)5.10 管理内存 这些对象与垃圾收集机制交互。 5.10.1 WeakRef WeakRef对象允许您保留对另一个对象的弱引用而不会阻止该对象被垃圾收集 new WeakRef(target) WeakRef实例的deref()方法返回该WeakRef的目标值如果目标值已被垃圾收集则未定义。 5.10.2 FinalizationRegistry 允许您在值被垃圾收集时请求回调。 let obj {}//创建一个对象new FinalizationRegistry(callbackFn) const registry new FinalizationRegistry(callbackFn)//注册一个需要监听的目标对象obj // register(target, heldValue) // register(target, heldValue, unregisterToken) // unregisterToken必须时对象,一般使用源对象就可以不指定的话无法注销 const sb Symbol.for(13) registry.register(obj,我是回调传递的值heldValue,obj); registry.unregister(obj)//此语句解绑不监听垃圾回收 function callbackFn(heldValue){console.log (heldValue);//我是回调传递的值heldValueconsole.log (垃圾回收了); }// obj指向另一个对象则手动内存回收时会回收掉{}对象 obj {b:hui} 5.11 控制抽象对象 控制抽象可以帮助构建代码特别是异步代码(例如不使用深度嵌套的回调)。 5.11.1 Iterator 它是所有其他迭代器类的超类 const arr [1,2,3] //创建一个迭代器,从现有的可迭代对象或迭代器对象创建一个Iterator实例 const i Iterator.from(arr) //创建一个迭代器 const i1 arr[Symbol.iterator]() console.log (i.next()); console.log (i1.next());5.11.2 AsyncIterator 5.11.3 Promise Promise对象表示异步操作的最终完成(或失败)及其结果值。 Promise的三种状态 pending: 初始状态既没完成也不拒绝。fulfilled: 表示操作成功完成rejected: 意味着操作失败。 5.11.3.1 构造函数 new Promise(executor) executor这是一个函数该函数由构造函数执行。它接收两个参数resolveFunc和rejectFunc 当通过new调用Promise构造函数时它返回一个Promise对象 当函数resolveFunc或rejectFunc被调用时promise对象将被解决。 注意如果你调用resolveFunc或rejectFunc并传递另一个Promise对象作为参数它可以说是“resolved”但仍然不是“settled”。 Promise()构造函数允许将基于回调的API转换为基于Promise的API。 以下是典型流程的总结: 当构造函数生成新的Promise对象时它也会生成一对对应的resolveFunc和rejectFunc函数执行器通常包装一些异步操作回调是在执行器代码中定义的因此它可以访问resolveFunc和rejectFunc使用resolveFunc和rejectFunc函数作为参数同步调用执行器(在构造Promise时)。异步任务的最终完成是通过resolveFunc或rejectFunc引起的作用与promise实例通信的。 如果先调用resolveFunc传递的值将被解析。pending 态 thenable被传递fulfilled态非thenable被传递rejected 态无效的值传递如果先调用rejectFunc承诺立即被拒绝。如果执行器抛出错误退出则承诺被拒绝。但是如果其中一个解析函数已经被调用(因此承诺已经被解析)则该错误将被忽略。 一旦promise确定它(异步)调用通过then()、catch()或finally()关联的任何其他处理程序 5.11.3.2 静态方法 Promise.all() 接受Promise的可迭代对象作为输入并返回一个Promise 当所有输入的promise都实现时(包括传递空可迭代对象时)返回的promise就会实现并带有一个兑现值数组。当输入的任何一个承诺被拒绝时它就会拒绝这是第一个拒绝原因。 该对象在所有给定的 Promise 都已经完成无论是完成还是被拒绝后才会解析。返回的 Promise 的解析值是一个数组每个元素都是一个对象表示对应的 Promise 的状态和值或拒绝原因。 Promise.allSettled() 接受Promise的可迭代对象作为输入并返回一个Promise 当所有输入的promise都完成时(包括传递空可迭代对象时)这个返回的promise就会完成并使用一个对象数组来描述每个promise的结果。 该对象在所有给定的 Promise 都已经完成时才会解析。但是如果任何一个 Promise 被拒绝Promise.all() 会立即拒绝拒绝的原因是第一个被拒绝的 Promise 的拒绝原因。 const promise1 new Promise((resolve,reject){resolve(成功1) }); const promise2 new Promise((resolve,reject){reject(失败2) }); const promise3 new Promise((resolve,reject){resolve(成功3) });Promise.all([promise1,promise2,promise3]).then(value {console.log (value); }).catch(e {console.log (错误e);})//错误失败2Promise.allSettled([promise1,promise2,promise3]).then(value {console.log (value); }).catch(e {console.log (错误e);}) // [ // {status: fulfilled,value: 成功1}, // {status: rejected,reason: 失败2}, // {status: fulfilled,value: 成功3} // ] Promise.any() 接受Promise的可迭代对象作为输入并返回一个Promise 当输入的任何一个承诺实现时返回的承诺就会实现并带有第一个实现值。当所有输入的承诺都被拒绝时(包括传递空可迭代对象时)它将拒绝并使用包含拒绝原因数组的AggregateError。 只有在所有 promises 都被拒绝时才会拒绝并且会返回一个 AggregateError表示所有 promises 的失败。 Promise.race() 方法接受Promise的可迭代对象作为输入并返回一个Promise。 这个返回的承诺与第一个承诺的最终状态一致。 相当于所有promise竞争第一个就是全局结果一旦有一个 promise 被拒绝就会立即拒绝而不管其他 promises 的状态 Promise.reject() 返回一个被给定原因拒绝的Promise对象。 Promise.resolve() 将给定的值“解析”为一个Promise。 如果值是一个promise则返回该promise;如果该值是一个then() Promise.resolve()将调用then()方法并使用它准备好的两个回调函数;否则返回的承诺将用该值来完成 Promise.withResolvers() 返回一个对象其中包含一个新的Promise对象和两个解析或拒绝它的函数对应于传递给Promise()构造函数执行器的两个参数 5.11.3.3 实例方法 Promise.prototype.catch() 在Promise被拒绝时调用的函数 Promise.prototype.finally() 调度一个函数当Promise被解决(完成或拒绝)时调用 这样可以避免在promise的then()和catch()处理程序中重复代码 Promise.prototype.then() 最多有两个参数:Promise的完成和拒绝情况的回调函数 语法then(onFulfilled)then(onFulfilled, onRejected) 当一个Promise被拒绝时它的.catch()方法将被调用。.catch()方法是专门用来处理Promise被拒绝的情况的。如果你在.then()方法中提供了两个函数参数第二个函数可以用来处理Promise被拒绝的情况但通常我们在.then()中只处理Promise被成功解决的情况将处理拒绝的逻辑放在.catch()中。这样的代码更清晰更易于理解。 5.11.4 GeneratorFunction 为生成器函数提供了方法。在JavaScript中每个生成器函数实际上都是一个GeneratorFunction对象 注意GeneratorFunction不是一个全局对象。可通过以下代码获得: const GeneratorFunction function* () {}.constructor; 语法 new GeneratorFunction(functionBody) new GeneratorFunction(arg1, functionBody) new GeneratorFunction(arg1, arg2, functionBody) new GeneratorFunction(arg1, arg2, /* …, */ argN, functionBody)GeneratorFunction(functionBody) GeneratorFunction(arg1, functionBody) GeneratorFunction(arg1, arg2, functionBody) GeneratorFunction(arg1, arg2, /* …, */ argN, functionBody) 示例 const GeneratorFunction function* () {}.constructor;const foo new GeneratorFunction(yield a;yield b;yield c; );let str ; for (const val of foo()) {str str val; }console.log(str);5.11.5 AsyncGeneratorFunction 为异步生成器函数提供了方法。在JavaScript中每个异步生成器函数实际上都是一个AsyncGeneratorFunction对象 注意AsyncGeneratorFunction不是一个全局对象。它可以通过计算下面的代码得到: const AsyncGeneratorFunction async function* () {}.constructor; 语法 new AsyncGeneratorFunction(functionBody) new AsyncGeneratorFunction(arg1, functionBody) new AsyncGeneratorFunction(arg1, arg2, functionBody) new AsyncGeneratorFunction(arg1, arg2, /* …, */ argN, functionBody)AsyncGeneratorFunction(functionBody) AsyncGeneratorFunction(arg1, functionBody) AsyncGeneratorFunction(arg1, arg2, functionBody) AsyncGeneratorFunction(arg1, arg2, /* …, */ argN, functionBody) 5.11.6 Generator Generator对象由生成器函数返回它同时符合可迭代协议和迭代器协议 //生成器函数和GeneratorFunction的区别是这个是静态创建函数GeneratorFunction是动态创建函数 function* generator() {yield 1;yield 2;yield 3; }//生成器对象 const gen generator(); // Generator { }console.log(gen.next().value); // 1 console.log(gen.next().value); // 2 console.log(gen.next().value); // 3 5.11.6.1 实例方法 Generator.prototype.next() 返回一个具有done和value两个属性的对象。还可以为next方法提供参数以便向生成器发送值 该值将作为yield表达式的结果赋值。例如在variable yield表达式中传递给.next()函数的值将被分配给variable Generator.prototype.return() 作用就像在当前挂起的位置将return语句插入到生成器的主体中这将完成生成器并允许生成器在与try…finally块。 Generator.prototype.throw() 作用就像在生成器的当前挂起位置插入了一条throw语句它通知生成器有错误条件并允许它处理错误或者执行清理和关闭自己。 5.11.7 AsyncGenerator 由async生成器函数返回它同时符合async可迭代协议和async迭代器协议。 异步生成器方法总是产生Promise对象 5.11.8 AsyncFunction 为异步函数提供了方法。在JavaScript中每个async函数实际上都是一个AsyncFunction对象。 注意AsyncFunction不是一个全局对象。可通过以下代码获得: const AsyncFunction async function () {}.constructor; 语法 new AsyncFunction(functionBody) new AsyncFunction(arg1, functionBody) new AsyncFunction(arg1, arg2, functionBody) new AsyncFunction(arg1, arg2, /* …, */ argN, functionBody)AsyncFunction(functionBody) AsyncFunction(arg1, functionBody) AsyncFunction(arg1, arg2, functionBody) AsyncFunction(arg1, arg2, /* …, */ argN, functionBody)5.12 反射 5.12.1 Reflect Reflect的所有属性和方法都是静态的(就像Math对象一样)。 Reflect 主要用于以函数式的方式替代一些对象操作 Reflect 代替基本操作有什么优点举个例子如果我们想要删除对象的属性通常我们会使用 delete 操作符如 delete obj.prop。但是delete 操作符有一些特殊的行为比如当你尝试删除一个不存在的属性或一个不可配置的属性时它不会抛出错误而是静默失败。 反观 Reflect 对象我们可以使用 Reflect.deleteProperty(obj, prop) 来达到同样的效果。与 delete 操作符不同如果删除失败Reflect 的方法会返回 false让我们能更明确地知道操作是否成功。 所以使用 Reflect 对象的方法我们可以不必记住每个操作的具体语法和特殊行为只需要记住 Reflect 的一致且直观的 API。这就是这句话的含义。5.12.1.1 静态方法 Reflect.apply() 使用指定的参数调用目标函数。 语法Reflect.apply(target, thisArgument, argumentsList) Reflect.construct() 方法类似于new操作符但作为一个函数。它相当于调用new target(…args)。它还允许指定不同的new。目标的价值。 语法Reflect.construct(target, argumentsList)Reflect.construct(target, argumentsList, newTarget) 相当于new构造函数并传递参数 Reflect.defineProperty() 类似于Object.defineProperty()但返回一个布尔值。 语法Reflect.defineProperty(target, propertyKey, attributes) Reflect.deleteProperty() 方法类似于删除操作符但作为一个函数。它从对象中删除属性。 语法Reflect.deleteProperty(target, propertyKey) Reflect.get() 方法类似于属性访问器语法但作为一个函数 语法Reflect.get(target, propertyKey)Reflect.get(target, propertyKey, receiver) Reflect.getOwnPropertyDescriptor() 类似于Object.getOwnPropertyDescriptor()。如果给定属性存在于对象上则返回该属性的属性描述符否则未定义。 语法Reflect.getOwnPropertyDescriptor(target, propertyKey) Reflect.getPrototypeOf() 方法类似于Object.getPrototypeOf()。它返回指定对象的原型。 语法Reflect.getPrototypeOf(target) Reflect.has() 方法类似于in操作符但作为一个函数。 语法Reflect.has(target, propertyKey) Reflect.isExtensible() 方法类似于Object.isExtensible()。它确定对象是否可扩展(是否可以向其添加新属性) 语法Reflect.isExtensible(target) Reflect.ownKeys() 方法返回目标对象自己的属性键数组。 语法Reflect.ownKeys(target) Reflect.preventExtensions() 方法类似于Object.preventExtensions()。它防止新属性被添加到对象中(即防止将来对对象进行扩展)。 语法Reflect.preventExtensions(target) Reflect.set() 方法类似于属性访问器和赋值语法但作为一个函数。 语法Reflect.set(target, propertyKey, value)Reflect.set(target, propertyKey, value, receiver) Reflect.setPrototypeOf() 方法类似于Object.setPrototypeOf()但返回一个布尔值。它设置指定对象的原型(即内部的[[prototype]]属性)。 语法Reflect.setPrototypeOf(target, prototype) 5.12.2 Proxy 使您能够为另一个对象创建代理该代理可以拦截和重新定义该对象的基本操作。 Proxy 则用于在对象操作上添加自定义行为。 //目标对象 const target {notProxied: original value,proxied: original value, }; //处理函数 const handler {get(target, prop, receiver) {if (prop proxied) {return replaced value;}return Reflect.get(...arguments);}, }; //创建代理 const proxy new Proxy(target, handler);console.log(proxy.notProxied); // original value console.log(proxy.proxied); // replaced value Proxy.revocable()静态方法创建一个可撤销的Proxy对象 const revocable Proxy.revocable({},{get(target, name) {return [[${name}]];},}, ); const proxy revocable.proxy; console.log(proxy.foo); // [[foo]]revocable.revoke();console.log(proxy.foo); // TypeError is thrown proxy.foo 1; // TypeError again delete proxy.foo; // still TypeError typeof proxy; // object, typeof doesnt trigger any trap 5.13 国际化 六、函数 6.1 概述 js中有四种类型的函数 正则函数可以返回任何东西;总是在调用后运行到完成生成器函数返回一个生成器对象可以使用yield操作符暂停和恢复异步函数返回一个Promise可以使用await操作符暂停和恢复异步生成器函数返回一个异步生成器对象yield和await操作符可以使用 每一类函数都有三种定义方法 声明表达式构造器 所有语法的不同 构造器、表达式和声明创建了完整的函数对象可以用new构造但是不能构造箭头函数和方法异步函数、生成器函数和异步生成器函数都是不可构造的。function 声明的函数被提升。其他语法不能提升并且在定义后才能访问值箭头函数和Function()构造器创建一个匿名函数意味着它们不能递归调用自己。递归调用箭头函数的一种方法是将其赋值给一个变量箭头函数语法不能访问arguments或this。Function()构造函数不能访问任何局部变量——它只能访问全局作用域。Function()构造函数导致运行时编译并且通常比其他语法慢 立即执行函数采用分组或void //分组 (function () {console.log(FOO!); })(); //void void function () {console.log(FOO!); }();有三种特殊的参数语法 如果没有传递值或未定义默认参数允许使用默认值初始化形式参数。rest形参允许将无限数量的参数表示为数组。解构允许将数组中的元素或对象中的属性拆分成不同的变量。 function myFunc({ a, b }, c 1, ...rest) {// You can access the values of a, b, c, and rest here }6.2 箭头函数表达式 箭头函数表达式是传统函数表达式的紧凑替代品在使用上有一些语义上的差异和故意的限制: 箭头函数对this、arguments或super没有自己的绑定因此不应该用作方法箭头函数不能用作构造函数。用new调用它们会抛出TypeError箭头函数不能在其函数体中使用yield也不能作为生成器函数创建。 只有当函数只有一个简单的参数时括号才可以省略。如果它有多个参数、没有参数、默认参数、解构参数或rest参数则需要在参数列表周围加上括号。 只有当函数直接返回表达式时才可以省略大括号。 箭头函数总是未命名的。如果箭头函数需要调用自身则使用命名函数表达式代替。您还可以将箭头函数分配给一个变量这样它就有了一个名称 直接返回对象字面量 const func () { foo: 1 };//这种报错 const func () ({ foo: 1 });//使用括号包裹箭头函数不能应用与方法中因为箭头函数没有自己的this const obj {i: 10,b: () console.log(this.i, this),//不应这么使用c() {console.log(this.i, this);}, };call()、apply()和bind()方法在箭头函数上调用时也没有用因为箭头函数是根据箭头函数定义的范围来建立this的而this值不会根据函数的调用方式而改变。 鉴于箭头函数的优先级 callback callback || () {}; callback callback || (() {});//加上括号避免callback ||()被解析为箭头函数的参数列表示例 const obj {num: 100, };globalThis.num 42;//正常函数this指向调用的对象为obj const add1 function (a, b, c) {return this.num a b c; }; //使用箭头函数this指向globalThis const add2 (a, b, c) this.num a b c;console.log(add1.call(obj, 1, 2, 3)); // 106console.log(add2.call(obj, 1, 2, 3)); // 48也许使用箭头函数的最大好处是使用setTimeout()和EventTarget.prototype.addEventListener()这样的方法它们通常需要某种闭包、call()、apply()或bind()来确保函数在适当的范围内执行。 addEventListener() const obj1 {count: 10,add(){const btn document.querySelector(button);btn.addEventListener(click,function(){// 传统函数this指向windowconsole.log (this.count);})} }const obj2 {count: 10,add(){const btn document.querySelector(button);// 箭头函数this指向objbtn.addEventListener(click,()console.log (this.count))} }obj1.add();//NaN obj2.add();//11setTimeout() const obj {count: 10,doSomethingLater() {setTimeout(function () {// 传统函数this指向windowthis.count;console.log(this.count);}, 300);}, };obj.doSomethingLater(); // logs NaNconst obj {count: 10,doSomethingLater() {// 箭头函数this指向objsetTimeout(() {this.count;console.log(this.count);}, 300);}, }; obj.doSomethingLater(); // logs 116.3 默认参数 语法 function fnName(param1 defaultValue1, /* …, */ paramN defaultValueN) {// … }6.4 get get语法将对象属性绑定到一个函数该函数将在查找该属性时被调用。它也可以在类上使用 语法 { get prop() { /* … */ } } { get [expression]() { /* … */ } }//还可以使用计算属性名称的表达式绑定到给定的函数getter必须完全没有参数。 //计算属性名 const expr function(){return foo };const obj {get [expr()]() {return bar;}, };console.log(obj.foo); // bar6.5 方法定义 方法定义是在对象初始化器中定义函数属性的较短语法。它也可以在类上使用 语法 ({property(parameters) {},*generator(parameters) {},async property(parameters) {},async *generator(parameters) {},// with computed keys[expression](parameters) {},*[expression](parameters) {},async [expression](parameters) {},async *[expression](parameters) {}, })6.6 剩余参数 剩余参数语法允许函数以数组的形式接受不确定数量的参数从而提供了一种在JavaScript中表示可变函数的方法 语法 function f(a, b, ...theArgs) {// … }rest参数不计入函数的length属性 rest和arguments的区别 arguments不是真正的数组rest是一个数组的实例arguments有一个被废弃的callee属性非严格模式使用基本参数时arguments和形参更新是同步的。rest从来不同步更新rest绑定所有参数但不包括…rest之前的参数arguments包含所有参数包含…rest function fun(a,f,...rests){console.log (Array.isArray(arguments));//falseconsole.log (Array.isArray(rests));//true }fun(1,3,4,5)//简单参数arguments更新a也更新 function fun2(a){arguments[0] 9console.log (a);//9 } fun2(2)//非简单参数(形参包含默认参数rest参数结构参数等)arguments更新a不更新 function fun3(ab1){arguments[0] 9console.log (a);//2 } fun3(2)6.7 set set语法将对象属性绑定到要在尝试设置该属性时调用的函数。它也可以在class上使用。 语法 { set prop(val) { /* … */ } } { set [expression](val) { /* … */ } }setter必须只有一个参数 6.8 Arguments对象 Arguments是一个可以在函数内部访问的类数组对象其中包含传递给该函数的实参的值。 类数组转化为数组 const args Array.prototype.slice.call(arguments); // or const args Array.from(arguments); // or const args [...arguments]; 生成html结构 function list(type) {let html ${type}lli;const args Array.prototype.slice.call(arguments, 1);html args.join(/lili);html /li/${type}l; // end listreturn html; }七、类 7.1 概述 类是创建对象的模板。它们用处理数据的代码封装数据。JS中的类是建立在原型之上的但也有一些类特有的语法和语义。 7.2 构造函数 构造函数方法是类的特殊方法用于创建和初始化该类的对象实例 这里有一些额外的语法限制 称为构造函数的类方法不能是getter、setter、async或生成器。一个类不能有多个构造函数方法 如果您不提供自己的构造函数那么将为您提供默认构造函数 如果你的类是基类默认构造函数为空:如果你的类是一个派生类默认构造函数调用父构造函数传递提供的任何参数 构造函数方法可以有一个返回值。基类可以从其构造函数返回任何值而派生类必须返回对象或未定义值否则将抛出TypeError。 如果父类构造函数返回一个对象该对象将被用作this值派生类的类字段将在此值上定义。这个技巧被称为“返回覆盖”它允许在不相关的对象上定义派生类的字段(包括私有字段)。 禁止将异步方法、生成器方法、访问器和类字段称为构造函数。私有名称不能称为#constructor。任何名为constructor的成员都必须是普通方法 7.3 继承 extends关键字可用于自定义类和内置对象的子类化 任何可以用new调用并具有prototype属性的构造函数都可以作为父类的候选对象。这两个条件必须同时成立——例如绑定函数和代理可以被构造但它们没有原型属性因此它们不能被子类化 7.4 私有属性 私有属性通过使用#前缀创建不能在类之外合法引用。 访问私有属性的唯一方法是通过点表示法并且只能在定义私有属性的类中这样做 这里有一些额外的语法限制 在类中声明的所有私有标识符必须是唯一的。名称空间在静态属性和实例属性之间共享。唯一的例外是两个声明定义了getter-setter对。私有标识符不能是#constructor 在Chrome控制台中运行的代码可以在类之外访问私有属性。这是一个仅针对devtools的JavaScript语法限制的放松 7.5 公有类字段 这里有一些额外的语法限制: 静态属性(字段或方法)的名称不能是prototype类字段(静态或实例)的名称不能是构造函数 7.6 静态 static关键字定义了类的静态方法或字段或者静态初始化块(有关此用法的更多信息请参阅链接)。静态属性不能在类的实例上直接访问。相反它们是在类本身上访问的。 7.7 静态初始化块 静态初始化块在类中声明。它包含要在类初始化期间求值的语句。这允许比静态属性更灵活的初始化逻辑例如使用try…从单个值捕获或设置多个字段。初始化是在当前类声明的上下文中执行的可以访问私有状态这允许类与在同一作用域中声明的其他类或函数共享其私有属性的信息

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

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

相关文章

网站推广营销潞城建设局网站

题目要求:判断一棵树是否为平衡二叉树 思路:递归地比较左右子树,只要有一棵子树不满足条件就说明这棵树不是平衡二叉树。本题采用迭代法较为复杂。 leetcode实战: 代码实现: 递归: 迭代:

商城网站都有什么功能设计交易平台哪个好

SoMeLVLM: A Large Vision Language Model for Social Media Processing 论文地址: https://arxiv.org/abs/2402.13022https://arxiv.org/abs/2402.13022发表在ACL 2024 1.概述 在线社交媒体平台涌现出海量的文本与视觉内容,深刻揭示了人们如何交流、互动以及自我表达。随着通…

发帖百度秒收录网站分享中太建设集团股份有限公司官方网站

引言 前端开发中,数据的复制是一个常见的操作。尤其是在处理对象和数组时,我们需要考虑的是一个浅拷贝还是深拷贝。那么,什么是深拷贝和浅拷贝?它们在前端开发中有什么作用?如何实现这两种拷贝?这是我们在…

对于Hash冲突的处理

对于Hash冲突的处理求最小冲突质数 for(int i = 100000; ; ++ i){bool flag = true;for(int j = 2; j * j <= i; ++ j)if(i % j == 0) {flag = false;break;}if(flag) {cout << i << endl;break;}

完整教程:事件驱动与CDS:基于FHIR R5 Subscriptions与Bulk Data的再考察(上)

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

关于SeaTunnel 达梦数据迁移无法自动建表的问题

关于SeaTunnel 达梦数据迁移无法自动建表的问题Posted on 2025-09-27 10:33 漂泊雪狼 阅读(0) 评论(0) 收藏 举报当sink库为达梦库时,schema_save_mode 设置为"CREATE_SCHEMA_WHEN_NOT_EXIST",希望它…

大模型agent综述:A Survey on Large Language Model based Autonomous Agents - 详解

大模型agent综述:A Survey on Large Language Model based Autonomous Agents - 详解2025-09-27 10:35 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; o…

电脑做服务器发布网站大连旅顺网站制作

在CSS中&#xff0c;我们要给一个元素定义样式&#xff0c;首先得把这个元素选出来&#xff0c;我在网上看了很多文章&#xff0c;再结合老师所讲的精华部分将平时比较常用的选择器整理出来分享给大家&#xff0c;哈哈哈一起学习一起进步&#xff01; https://blog.csdn.net/ha…

微服务去掉认证的功能

微服务去掉认证的功能1.概述 我们的微服务是通过网关做统一安全认证的,服务的后端接口不需要做安全认证,有些情况下,我们引入了 spring-authrization-server 的依赖,这个时候服务就会自动启动认证服务,当访问接口…

INNER JOIN LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN

INNER JOIN (内连接)定义:INNER JOIN 返回的是在两个表中满足连接条件的所有匹配记录。 如果某个记录在其中一个表中没有匹配的记录,则不会出现在结果集中。语法: SELECT columns FROM table1 INNER JOIN table2 ON…

进程调度的时机,切换与过程

需要进行进程调度的情况 1.当前进程主动放弃处理机 1.正常终止 2.发生异常终止 3主动请求阻塞 2.当前进程被动放弃处理机 1.分配给进程的时间片用完 2.有更紧急的事情处理(io中断) 3有跟高优先级的进程进入就绪队列 …

python+springboot+uniapp基于微信小程序的巴马旅居养老系统 旅游养老小程序 - 详解

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

网站开发项目团队上海游玩攻略必去的地方

随着双十一购物狂欢节的临近&#xff0c;无数准父母和年轻家长开始摩拳擦掌&#xff0c;准备为家中的小宝贝抢购一系列高品质、实用的母婴用品。在这个年度最大的电商促销活动中&#xff0c;选择对的产品不仅能够节省开支&#xff0c;更能确保宝宝的健康成长与舒适生活。以下是…

企业自助建站的网站柳市网站建设

阿里云2核4G服务器租用优惠价格&#xff0c;轻量2核4G服务器165元一年、u1服务器2核4G5M带宽199元一年、云服务器e实例30元3个月&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接如下图&#xff1a; 阿里云2核4G服务器优惠价格 轻量应用服务器2核2G4M带宽、60GB高效…

深入解析:六维力传感器材质选择:影响性能与精度的关键因素

深入解析:六维力传感器材质选择:影响性能与精度的关键因素pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Conso…

按键精灵安卓/ios辅助工具,脚本开发新手教程ui界面介绍 - 教程

按键精灵安卓/ios辅助工具,脚本开发新手教程ui界面介绍 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Co…

P3197fwx - FanWenxuan

题目描述 监狱有n个房间,每个房间关押一个犯人,有m种宗教,每个犯人会信仰其中一种。如果相邻房间的犯人的宗教相同,就可能发生越狱,求有多少种状态可能发生越狱。 答案对100,003取模。 输入格式 输入只有一行两个…

网站建设与管理复习知识点山东兴华建设集团有限公司网站

在看文档的时候测试了一下demo&#xff0c;然后发现了一个有意思的东西&#xff0c;自定义滑块为带边框的圆形。 在设置的时候边框总是和预期的有点误差&#xff0c;后来发现了这样一个计算方式可以画一个比较标准的圆。&#xff08;ABCDEF在下方代码块内&#xff09; 滑块的…

2025年AI大模型赋能智能座舱研究报告:技术、资本与市场|附20+份报告PDF、数据仪表盘汇总下载

原文链接:https://tecdat.cn/?p=43950原文出处:拓端抖音号@拓端tecdat当你在驾驶时无需低头看仪表,语音唤醒座舱就能自动联动香氛与氛围灯,甚至能模糊说出“那首关于星空的歌”就被精准识别——智能座舱早已跳出“…

专题:2025年AI Agent智能体行业洞察报告|附110+份报告PDF、数据仪表盘汇总下载

原文链接:https://tecdat.cn/?p=43967原文出处:拓端抖音号@拓端tecdat2025年,AI Agent终于从“技术概念”走进企业实操场景——HR用它搞定数万份简历初筛,零售用它缩短报告生成时间,制造用它提升研发效率,这一年…