ES6 基础知识
1.let 和 const
在ES6之前,js只有全局作用域和函数作用域,ES6中let关键字为其引入了块级作用域。
1 2 3 4 5 6 7 | //{}代码块 { var a = 5; let b = 6; } console.log(a); //5 console.log(b); //b is undefined |
let声明的变量只能在其所在的代码块内才能访问,var声明的变量由于是全局变量,因此可以在代码块外访问
const用来定义常量,相当于java中的final关键字。
并且const声明常量之后就必须立即初始化!
2.暂时性死区
var声明的变量可以在声明之前使用,相当于默认为其声明其值为undefined了;
但是,let声明的变量一旦用let声明,那么在声明之前,此变量都是不可用的,术语称为“暂时性死区”。
1 2 3 4 5 | console.log(a); //undefined var a=8; console.log( "----------" ); console.log(b); //控制台报错 let b=9; |
所以我们要养成变量先声明再使用的好习惯。
3.解构赋值
以前,为变量赋值,只能直接指定值。
1 2 3 | let a = 1; let b = 2; let c = 3; |
ES6 允许写成下面这样。可以理解为“模式匹配”。
1 | let [a, b, c] = [1, 2, 3]; |
如果解构不成功,变量的值就等于undefined。
1 2 3 4 | let [x, y, ...z] = [ 'a' ]; x // "a" y // undefined z // [] |
另一种情况是不完全解构,即等号左边的模式,只匹配一部分的等号右边的数组。这种情况下,解构依然可以成功。
1 2 3 4 5 6 7 8 | let [x, y] = [1, 2, 3]; x // 1 y // 2 let [a, [b], d] = [1, [2, 3], 4]; a // 1 b // 2 d // 4 |
4.字符串的扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //Unicode表示法 "\u{码点}" "\u{41}\u{42}\u{43}" //"ABC" let str = "書剑恩仇录" ; str.codePointAt(0).toString(16); //返回字符的码点并由十进制转到16进制---66f8 String.fromCodePoint(0x66f8); //返回码点对应的字符---書 for ( let a of str){ console.log(a); } //for...of循环遍历字符串中每个字符挨个输出字符 str.at(0); //返回指定位置的字符,目前只是提案 str.startsWith( '書' ,0); //从指定位置往后开始检查,是否以“書”开始,位置参数可省略,默认为0 str.endsWith( '剑' ,1); //从指定位置向前检查,是否以“剑”结束 str.includes( '恩' ,1); //同上,不再啰嗦 str.repeat(2); //字符串重复指定次数“書剑恩仇录書剑恩仇录”,小数取整,Infinity和负数报错 str.padStart(8, 'ab' ); //指定字符从前开始补直到字符串长度符合要求,"aba書剑恩仇录" str.padEnd(8, 'ab' ); //指定字符从后开始补直到字符串长度符合要求,"書剑恩仇录aba",若长度小于原长度,返回原字符串,上同 |
模板字符串
模板字符串采用反引号 `
标识,并且模板字符串中的空格、换行将在输出时有所保留。
传统的 JavaScript 语言,输出模板通常是这样写的。
1 2 3 4 5 6 | $( '#result' ).append( 'There are <b>' + basket.count + '</b> ' + 'items in your basket, ' + '<em>' + basket.onSale + '</em> are on sale!' ); |
上面这种写法相当繁琐不方便,ES6 引入了模板字符串解决这个问题。
1 2 3 4 5 | $( '#result' ).append(` There are <b>${basket.count}</b> items in your basket, <em>${basket.onSale}</em> are on sale! `); |
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 普通字符串 `In JavaScript '\n' is a line-feed.` // 多行字符串 `In JavaScript this is not legal.` console.log(` string text line 1 string text line 2`); // 字符串中嵌入变量 let name = "Bob" , time = "today" ; `Hello ${name}, how are you ${time}?` |
5.正则的扩展
RegExp 构造函数
在 ES5 中,RegExp构造函数的参数有两种情况。
1 2 3 4 5 6 7 8 9 | //第一种情况是,参数是字符串,这时第二个参数表示正则表达式的修饰符(flag)。 var regex = new RegExp( 'xyz' , 'i' ); // 等价于 var regex = /xyz/i; //第二种情况是,参数是一个正则表示式,这时会返回一个原有正则表达式的拷贝。 var regex = new RegExp(/xyz/i); // 等价于 var regex = /xyz/i; |
但是,ES5 不允许此时使用第二个参数添加修饰符,否则会报错。
1 2 | var regex = new RegExp(/xyz/, 'i' ); // Uncaught TypeError: Cannot supply flags when constructing one RegExp from another |
ES6 改变了这种行为。如果RegExp构造函数第一个参数是一个正则对象,那么可以使用第二个参数指定修饰符。而且,返回的正则表达式会忽略原有的正则表达式的修饰符,只使用新指定的修饰符。
1 2 | new RegExp(/abc/ig, 'i' ).flags // "i" |
上面代码中,原有正则对象的修饰符是ig,它会被第二个参数i覆盖。
6.数值的扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | //从 ES5 开始,在严格模式之中,八进制就不再允许使用前缀0表示,ES6 进一步明确,要使用前缀0o表示。 //如果要将0b和0o前缀的字符串数值转为十进制,要使用Number方法。 Number( '0b111' ) // 7 Number( '0o10' ) // 8 //Number.isFinite()用来检查一个数值是否为有限的(finite),即不是Infinity。 Number.isFinite(0.1); // true Number.isFinite(NaN); // false Number.isFinite(Infinity); // false Number.isFinite( '0.1' ); // false Number.isFinite( true ); // false //传统方法会先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效 isFinite( "25" ) // true Number.isFinite( "25" ) // false //Number.isNaN()用来检查一个值是否为NaN。 Number.isNaN(NaN) // true Number.isNaN(15) // false Number.isNaN( '15' ) // false Number.isNaN( true ) // false Number.isNaN(9/NaN) // true Number.isNaN( 'true' / 0) // true Number.isNaN( 'true' / 'true' ) // true //传统方法会先调用Number()将非数值的值转为数值,再进行判断,而这两个新方法只对数值有效 isNaN( "NaN" ) // true Number.isNaN( "NaN" ) // false //ES6 将全局方法parseInt()和parseFloat(),移植到Number对象上面,行为完全保持不变。 // ES5的写法 parseInt( '12.34' ) // 12 parseFloat( '123.45#' ) // 123.45 // ES6的写法 Number.parseInt( '12.34' ) // 12 Number.parseFloat( '123.45#' ) // 123.45 //Number.isInteger()用来判断一个数值是否为整数。 Number.isInteger(25) // true Number.isInteger(25.0) // true Number.isInteger(25.1) // false Number.isInteger() // false Number.isInteger( null ) // false Number.isInteger( '15' ) // false Number.isInteger( true ) // false //ES6 在Number对象上面,新增一个极小的常量Number.EPSILON。根据规格,它表示 1 与大于 1 的最小浮点数之间的差。 Number.EPSILON === Math.pow(2, -52) // true Number.EPSILON // 2.220446049250313e-16 Number.EPSILON.toFixed(20) // "0.00000000000000022204" //ES6 引入了Number.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER这两个常量,用来表示这个范围的上下限。 Number.MAX_SAFE_INTEGER === Math.pow(2, 53) - 1 // true Number.MAX_SAFE_INTEGER === 9007199254740991 // true Number.MIN_SAFE_INTEGER === -Number.MAX_SAFE_INTEGER // true Number.MIN_SAFE_INTEGER === -9007199254740991 // true //ES6 在 Math 对象上新增了 17 个与数学相关的方法。所有这些方法都是静态方法,只能在 Math 对象上调用。 Math.trunc(4.1) // 4 Math.trunc方法用于去除一个数的小数部分,返回整数部分。 Math.sign(-5) // -1 Math.sign方法用来判断一个数到底是正数、负数、还是零 Math.cbrt( '8' ) // 2 Math.cbrt方法用于计算一个数的立方根。 //........ |
7.函数的扩展
参数默认值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ES5中的写法 function log(x, y) { //y = y || 'World'; --> 这种写法如果y是false则不起作用,所以用下面的方式复制 if ( typeof y === 'undefined' ) { y = 'World' ; } console.log(x, y); } log( 'Hello' ) // Hello World ES6中的写法 function log(x, y = 'World' ) { console.log(x, y); } log( 'Hello' ) // Hello World |
与解构赋值默认值的结合
1 2 3 | function m1({x = 0, y = 0} = {}) { return [x, y]; } |
作用域
1 2 3 4 5 6 7 8 | let x = 1; function f(y = x) { let x = 2; console.log(y); } f() // 1 |
参数y的默认值等于变量x。调用函数f时,参数形成一个单独的作用域。在这个作用域里面,默认值变量x指向第一个参数x,而不是全局变量x,所以输出是2。
name属性
1 2 | function foo() {} foo.name // "foo" |
箭头函数
1 2 3 4 5 6 7 8 9 10 | var f = v => v; // 等同于 var f = function (v) { return v; }; //如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分。 var f = () => 5; // 等同于 var f = function () { return 5 }; |
8.数组的扩展
扩展运算符(spread)是三个点(…)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | //----------------------------复制数组 // ES5的 写法 const a1 = [1, 2]; const a2 = a1.concat(); a2[0] = 2; a1 // [1, 2] // ES6的 写法 const a1 = [1, 2]; // 写法一 const a2 = [...a1]; // 写法二 const [...a2] = a1; //-----------------------------合并数组 const arr1 = [ 'a' , 'b' ]; const arr2 = [ 'c' ]; const arr3 = [ 'd' , 'e' ]; // ES5 的合并数组 arr1.concat(arr2, arr3); // [ 'a', 'b', 'c', 'd', 'e' ] // ES6 的合并数组 [...arr1, ...arr2, ...arr3] // [ 'a', 'b', 'c', 'd', 'e' ] |
Array.from方法用于将两类对象转为真正的数组
1 | Array. from ([1, 2, 3]) // [1, 2, 3] |
Array.of方法用于将一组值,转换为数组。
1 | Array.of(3, 11, 8) // [3,11,8] |
数组实例的copyWithin方法,在当前数组内部,将指定位置的成员复制到其他位置(会覆盖原有成员),然后返回当前数组。也就是说,使用这个方法,会修改当前数组。
1 2 3 | //Array.prototype.copyWithin(target, start = 0, end = this.length) [1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5] --> 上面代码表示将从 3 号位直到数组结束的成员(4 和 5),复制到从 0 号位开始的位置,结果覆盖了原来的 1 和 2。 |
数组实例的find方法,用于找出第一个符合条件的数组成员。它的参数是一个回调函数,所有数组成员依次执行该回调函数,直到找出第一个返回值为true的成员,然后返回该成员。如果没有符合条件的成员,则返回undefined。
1 2 3 4 5 6 | [1, 4, -5, 10].find((n) => n < 0) // -5 [1, 5, 10, 15].find(function(value, index, arr) { return value > 9; }) // 10 |
数组实例的findIndex方法的用法与find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
1 2 3 | [1, 5, 10, 15].findIndex(function(value, index, arr) { return value > 9; }) // 2 |
fill方法使用给定值,填充一个数组。
1 2 3 4 5 | [ 'a' , 'b' , 'c' ].fill(7) // [7, 7, 7] new Array(3).fill(7) // [7, 7, 7] |
entries(),keys()和values()——用于遍历数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | for ( let index of [ 'a' , 'b' ].keys()) { console.log(index); } // 0 // 1 for ( let elem of [ 'a' , 'b' ].values()) { console.log(elem); } // 'a' // 'b' for ( let [index, elem] of [ 'a' , 'b' ].entries()) { console.log(index, elem); } // 0 "a" // 1 "b" //如果不使用for...of循环,可以手动调用遍历器对象的next方法,进行遍历。 let letter = [ 'a' , 'b' , 'c' ]; let entries = letter.entries(); console.log(entries.next().value); // [0, 'a'] console.log(entries.next().value); // [1, 'b'] console.log(entries.next().value); // [2, 'c'] |
includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似
1 2 3 | [1, 2, 3].includes(2) // true [1, 2, 3].includes(4) // false [1, 2, NaN].includes(NaN) // true |
数组的空位指,数组的某一个位置没有任何值。比如,Array构造函数返回的数组都是空位。
1 2 3 4 | Array(3) // [, , ,] 0 in [undefined, undefined, undefined] // true 0 in [, , ,] // false |
9.对象的扩展
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //ES6 允许直接写入变量和函数,作为对象的属性和方法。这样的书写更加简洁。 function f(x, y) { return {x, y}; } // 等同于 function f(x, y) { return {x: x, y: y}; } f(1, 2) // Object {x: 1, y: 2} //JavaScript 定义对象的属性,有两种方法。 // 方法一 obj.foo = true ; // 方法二 obj[ 'a' + 'bc' ] = 123; var obj = { foo: true , abc: 123 }; |
10.Symbol
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型,前六种是:undefined、null、布尔值(Boolean)、字符串(String)、数值(Number)、对象(Object)。
1 2 3 4 | let s = Symbol(); typeof s // "symbol" |
上面代码中,变量s就是一个独一无二的值。typeof运算符的结果,表明变量s是 Symbol 数据类型,而不是字符串之类的其他类型。
11.Set和Map
ES6 提供了新的数据结构 Set。它类似于数组,但是成员的值都是唯一的,没有重复的值。
1 2 3 4 5 6 7 8 | const s = new Set(); [2, 3, 5, 4, 5, 2, 2].forEach(x => s.add(x)); for ( let i of s) { console.log(i); } // 2 3 5 4 |
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object 结构提供了“字符串—值”的对应,Map 结构提供了“值—值”的对应,是一种更完善的 Hash 结构实现。如果你需要“键值对”的数据结构,Map 比 Object 更合适。
1 2 3 4 5 6 7 8 9 | const m = new Map(); const o = {p: 'Hello World' }; m. set (o, 'content' ) m. get (o) // "content" m.has(o) // true m.delete(o) // true m.has(o) // false |
12.Proxy与Reflect
Proxy 用于修改某些操作的默认行为,等同于在语言层面做出修改,所以属于一种“元编程”(meta programming),即对编程语言进行编程
实例:使用 Proxy 实现观察者模式
观察者模式(Observer mode)指的是函数自动观察数据对象,一旦对象有变化,函数就会自动执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 | const person = observable({ name: '张三' , age: 20 }); function print() { console.log(`${person.name}, ${person.age}`) } observe(print); person.name = '李四' ; // 输出 // 李四, 20 |
13.Promise
Promise 是异步编程的一种解决方案,比传统的解决方案–回调函数和事件--更合理和更强大。它由社区最早提出和实现,ES6将其写进了语言标准,统一了语法,原生提供了Promise
所谓Promise ,简单说就是一个容器,里面保存着某个未来才回结束的事件(通常是一个异步操作)的结果。从语法上说,Promise是一个对象,从它可以获取异步操作的消息。
Promise 对象的状态不受外界影响
三种状态:
pending:进行中
fulfilled : 已经成功
rejected :已经失败
ajax的异步:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | $(function(){ $( '#send' ).click(function(){ $.ajax({ type: "GET" , url: "test.json" , data: {username:$( "#username" ).val(), content:$( "#content" ).val()}, dataType: "json" , success: function(data){ $( '#resText' ).empty(); //清空resText里面的所有内容 var html = '' ; $.each(data, function(commentIndex, comment){ html += '<div class="comment"><h6>' + comment[ 'username' ] + ':</h6><p class="para"' + comment[ 'content' ] + '</p></div>' ; }); $( '#resText' ).html(html); } }); }); }); |
上面的例子实现了一个类似于表单提交的功能。
Promise的异步:
1 2 3 4 5 6 7 8 9 10 | let promise = new Promise(function(resolve, reject) { console.log( 'Promise' ); //实例化后立即执行 resolve(); //任务(成功)完成 }); promise.then(function() { console.log( 'resolved.' ); //任务结束执行 }); console.log( 'Hi!' ); //在实例化promise的同时,执行 |
14.Iterator接口
1 2 3 4 5 6 7 8 9 10 | for ... in 循环:只能获取对象的键名 for ...of循环:可以获得键值,只返回具有数字索引的属性(键或值) var arr = [ 'a' , 'b' , 'c' , 'd' ]; for ( let a in arr) { console.log(a); // 0 1 2 3 } for ( let a of arr) { console.log(a); // a b c d } |
15.async函数
async就表示asynchronous(异步的),async函数会返回一个Promise对象,自然能够调用其方法:
promise.then(success()).catch(error()).finally(function(){});
1 2 3 4 5 6 7 8 9 | async function getStockPriceByName(name) { const symbol = await getStockSymbol(name); const stockPrice = await getStockPrice(symbol); return stockPrice; //stockPrice是一个promise对象 } getStockPriceByName( 'goog' ).then(function (result) { console.log(result); }); |
16.class
1 2 3 4 5 6 7 8 9 10 | class ColorPoint extends Point { constructor(x, y, color) { super(x, y); // 调用父类的constructor(x, y) this .color = color; } toString() { return this .color + ' ' + super.toString(); // 调用父类的toString() } } |
17.模块化
1 2 3 4 5 6 7 8 9 | //lib.js var counter = 3; function incCounter() { counter++; } module.exports = { counter: counter, incCounter: incCounter, }; |
这是一个js模块,对外暴露两个属性counter(变量)、incCounter(函数),然后再去加载这个模块
这样就可以去调用该模块对外暴露的属性了:
1 2 3 4 5 6 | // main.js var mod = require( './lib' ); console.log(mod.counter); // 3 mod.incCounter(); console.log(mod.counter); // 3 |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· 2 本地部署DeepSeek模型构建本地知识库+联网搜索详细步骤