ES6 语法详解
共计 10695 个字符,预计需要花费 27 分钟才能阅读完成。
ES6(ECMAScript 2015)是 JavaScript 的一个版本,它于 2015 年发布。ES6 引入了很多新的语法和功能,使得 JavaScript 更加强大、灵活和易于使用。
一、块级作用域:
ES6 引入了let 和 const 关键字,可以在块级作用域中声明变量,解决了以前使用 var 声明变量可能导致的问题。在 ES6 之前,JavaScript 中的变量声明使用var
关键字,它具有函数作用域而不是块级作用域。这意味着使用**var**
声明的变量可以在其所在的函数内部任何位置访问,而不仅仅是在声明的块级作用域内。
1、let
关键字:
let
关键字用于声明可变的变量,它的作用范围限定在当前的块级作用域内,包括花括号({})内部的任何代码块。在同一个作用域内,不能重复声明同名的let
变量。
function example() {
if (true) {
let x = 10; // 声明一个块级作用域内的变量 x
console.log(x); // 输出 10
}
console.log(x); // 报错,x 未定义
}
example();
2、const
关键字:
const
关键字用于声明常量,它的作用范围也是在当前的块级作用域内。与let
不同,const
声明的变量是不可变的,即不能被重新赋值。同时,const
声明的变量必须在声明时进行初始化,且不能再次修改其值。
function example() {
const PI = 3.14159; // 声明一个常量PI
console.log(PI); // 输出 3.14159
PI = 3.14; // 报错,常量不能被重新赋值
}
example();
二、箭头函数
ES6 引入了箭头函数=>语法,简化了函数的定义和使用
1、箭头函数可以简化的函数定义
// 传统函数定义
function add(a, b) {
return a + b;
}
// 箭头函数定义
const add = (a, b) => a + b;
2、隐式返回值
指箭头函数中省略了return
关键字,并且直接返回一个表达式的值。这意味着箭头函数可以在一行代码中完成函数体的定义和返回值的指定
// 传统函数定义
function multiply(a, b) {
return a * b;
}
// 箭头函数定义
const multiply = (a, b) => a * b;
//箭头函数中省略了return关键字,并且直接返回了a * b的结果。这就是隐式返回值的概念
需要注意的是,隐式返回值只适用于一行代码的情况。如果函数体有多行代码或者需要进行复杂的逻辑处理,仍然需要使用传统的函数定义并显式地使用return
关键字。
const calculate = (a, b) => {
if (a > b) {
return a - b;
} else {
return b - a;
}
};
在上述示例中,根据条件判断使用了显式返回值(使用return
关键字),而在其他情况下则使用了隐式返回值。这样可以兼顾简洁性和灵活性。
3、使用箭头函数作为回调函数
在 JavaScript 中,回调函数是指作为参数传递给其他函数的函数。在某些情况下,我们需要在回调函数中定义一些简单的逻辑来处理数据或完成一些操作。使用箭头函数作为回调函数可以使代码更加简洁,提高开发效率。
const numbers = [1, 2, 3, 4, 5];
// 传统函数定义
//map()方法用于对数组中的每个元素进行处理,并返回一个新的数组
const square = numbers.map(function (number) {
return number * number;
});
//在传统的函数定义中,我们需要使用function关键字,同时需要使用return关键字来指定返回值。
// 箭头函数定义
const square = numbers.map((number) => number * number);
//在箭头函数中,由于只有一行代码,我们可以使用隐式返回值的方式来简化函数定义和返回值的指定。
需要注意的是,在使用箭头函数作为回调函数时,要根据具体的情况来考虑是否需要使用括号来包裹参数。如果只有一个参数,可以省略括号,但如果没有参数或者有多个参数,则需要使用括号。
4、使用箭头函数绑定外部 this 值
箭头函数可以绑定外部 this
值,这是因为箭头函数没有自己的 this
上下文。箭头函数的 this
值继承了它所在上下文的 this
值。当我们在箭头函数中使用 this
时,它指向的就是箭头函数所在的上下文中的 this
值。
export default {
data() {
return {
message: 'Hello, World!'
}
},
mounted() {
setTimeout(() => {
console.log(this.message) // 输出:Hello, World!
}, 1000)
}
}
在上述代码中,我们在组件的 mounted
钩子函数中使用了一个 setTimeout
函数,该函数中包含一个箭头函数作为回调函数。由于箭头函数继承了它所在上下文的 this
值,因此在箭头函数中我们可以访问到组件实例的 this
值。
三、模板字符串
在 ES6 中,模板字符串是一种特殊的字符串语法,使用反引号(`)来包裹字符串内容。它允许在字符串中插入表达式,并且支持多行字符串的定义,提供了更加灵活和方便的字符串处理方式。
1、字符串插值
使用${}
语法,在模板字符串中嵌入表达式或变量。这样可以方便地将变量的值插入到字符串中
const name = 'SHANDONG';
const message = `Hello, ${name}!`;
console.log(message); // 输出:Hello, SHANDONG!
2、多行字符串
使用模板字符串可以方便地定义多行字符串,而无需使用\n
进行换行操作
const multiline = `
This is
a multiline
string.
`;
console.log(multiline);
// 输出:
// This is
// a multiline
// string.
3、嵌套使用
模板字符串可以嵌套使用,可以在一个模板字符串中插入另一个模板字符串
const name = 'Alice';
const message = `Hello, ${`Welcome, ${name}!`} How are you?`;
console.log(message); // 输出:Hello, Welcome, Alice! How are you?
总而言之,ES6 中的模板字符串提供了一种更加灵活和方便的字符串处理方式。它支持字符串插值,在字符串中嵌入表达式或变量;支持定义多行字符串,无需使用\n
进行换行;还可以嵌套使用,将一个模板字符串插入到另一个模板字符串中。这些特性使得模板字符串在处理复杂字符串逻辑时更加简洁和直观。
四、解构赋值
一种特殊的赋值语法,可以方便地将数组或对象中的值解构到变量中;
这样可以简化变量的声明和赋值操作,提高代码的可读性和可维护性。
1、数组解构
使用数组解构可以将数组中的元素解构到变量中。解构时需要使用方括号([])来包裹变量名
const numbers = [1, 2, 3, 4];
const [a, b, c, d] = numbers;
console.log(a, b, c, d); // 输出:1 2 3 4
在上面的例子中,数组中的第一个元素被解构到变量a
中,第二个元素被解构到变量b
中,以此类推。如果数组中的元素数量少于变量数量,未被解构的变量将会是undefined
。
const numbers = [1, 2, 3];
const [a, b, c, d] = numbers;
console.log(a, b, c, d); // 输出:1 2 3 undefined
2、对象解构
使用对象解构可以将对象中的属性解构到变量中。解构时需要使用花括号({})来包裹变量名,并且变量名要与对象属性名相同
const person = { name: 'asd', age: 20 };
const { name, age } = person;
console.log(name, age); // 输出:asd 20
在上面的例子中,对象中的name
属性被解构到变量name
中,age
属性被解构到变量age
中。如果对象中没有对应的属性,变量将会是undefined
。
const person = { name: 'asd', age: 20 };
const { name, age,sex } = person;
console.log(name, age,sex); // 输出:asd 20 undefined
3、默认值
可以为解构赋值设置默认值,当变量未被解构时将会使用默认值。
const numbers = [1, 2];
const [a, b, c = 3] = numbers;
console.log(a, b, c); // 输出:1 2 3
在上面的例子中,变量c
设置了默认值为3
。由于数组中只有两个元素,变量c
未被解构,因此使用了默认值。
4、剩余操作符
可以使用剩余操作符(...)将剩余的数组元素或对象属性解构到一个新的数组或对象中。
const numbers = [1, 2, 3, 4];
const [a, b, ...rest] = numbers;
console.log(a, b, rest); // 输出:1 2 [3, 4]
const person = { name: 'Alice', age: 20, gender: 'female' };
const { name, ...rest } = person;
console.log(name, rest); // 输出:Alice { age: 20, gender: 'female' }
在上面的例子中,使用剩余操作符可以将剩余的数组元素或对象属性解构到一个新的数组或对象中。在数组解构中,剩余操作符需要放在最后;在对象解构中,剩余操作符可以放在任意位置。
五、默认参数
在 ES6 中,可以为函数的参数设置默认值,这样在函数调用时,如果没有传递该参数或传递的值为 undefined,就会使用默认值。这样可以简化函数的调用,避免出现 undefined 的情况。
1、设置默认值
在函数定义时,可以通过赋值运算符(=)来为参数设置默认值。
function greet(name = 'Guest') {
console.log(`Hello, ${name}!`);
}
greet(); // 输出:Hello, Guest!
greet('Alice'); // 输出:Hello, Alice!
在上面的例子中,greet
函数的name
参数设置了默认值为'Guest'
。当没有传递参数或传递的参数为undefined
时,将会使用默认值
2、默认值表达式
function multiply(a, b = 2 * a) {
return a * b;
}
console.log(multiply(5)); // 输出:50
console.log(multiply(5,2)); // 输出:10
在上面的例子中,multiply
函数的b
参数设置了默认值为2 * a
。当没有传递第二个参数时,将会使用默认值,计算结果为 b=5 * 2 = 10,a*b=5*10=50;当传递第二个参数,就会直接计算 a*b=5 * 2 = 10
3、
默认参数对 arguments 对象的影响
使用默认参数不会影响 arguments 对象的长度
function sum(a, b = 0) {
console.log(arguments.length);
return a + b;
}
console.log(sum(1)); // 输出:1,返回:1
console.log(sum(1, 2)); // 输出:2,返回:3
sum
函数的b
参数设置了默认值为0
。即使没有传递第二个参数,arguments 对象的长度仍然是 1。
需要注意的是,默认参数的作用域是函数内部,而不是全局作用域。这意味着默认参数可以访问函数体内的其他变量和参数,但不能访问函数外部的变量。
六、Promise
Promise 是一种用于处理异步操作的对象。它可以将异步操作封装成一个 Promise 对象,通过 then()
方法来添加回调函数,当异步操作完成时自动执行回调函数。
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
delay(1000).then(() => console.log('1 秒后输出该信息'));
在上面的例子中,定义了一个 delay()
函数,该函数返回一个 Promise 对象。该 Promise 对象会在指定的时间间隔之后自动执行 resolve()
方法,从而触发 then()
方法中设置的回调函数。使用 Promise 对象可以使异步操作的代码更加清晰、简洁,并且可以避免回调地狱的问题。
Promise 对象还提供了一些其他的方法,例如 catch()
方法可以捕获异步操作中的异常,并且可以通过 Promise.all()
方法来并行处理多个异步操作。
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = new Promise((resolve, reject) => {
setTimeout(resolve, 1000, '3 秒后输出该信息');
});
Promise.all([promise1, promise2, promise3]).then(values => {
console.log(values); // 输出:[1, 2, "3 秒后输出该信息"]
});
在上面的例子中,我们通过 Promise.resolve()
方法来创建了两个 Promise 对象,并且通过 new Promise()
方法创建了一个延时执行的 Promise 对象。我们将三个 Promise 对象放入了一个数组中,并且使用 Promise.all()
方法来并行处理这些异步操作。当所有异步操作都完成时,then()
方法中设置的回调函数将会被自动执行。
总的来说,平时使用:
jiekouming().then((res)=>{
console.log(res)
})
七、简化对象字面量的语法
ES6 简化对象字面量的语法主要包括两个方面的改进:属性名和方法名的简写、计算属性名。
1、属性名和方法名的简写
在 ES6 之前,如果我们需要将一个变量作为对象的属性名,通常需要使用计算属性名。例如:
const obj = { [propName]: 'value'};
在 ES6 中,我们可以使用属性名和方法名的简写来更加方便地创建对象。
const name = 'John';
const age = 20;
const obj = {
name,
age,
sayHi() {
console.log(`Hi, my name is ${this.name}, I'm ${this.age} years old.`);
}
};
obj.sayHi(); // 输出:Hi, my name is John, I'm 20 years old.
在上面的例子中,我们使用了属性名和方法名的简写语法,将变量 name
和 age
直接作为了对象的属性名。同时,我们也定义了一个 sayHi()
方法,并且在对象初始化时直接将其作为了一个属性。
2、计算属性名
ES6 提供了计算属性名的语法,允许我们在对象字面量中使用表达式来作为属性名。
const propName = 'size';
const obj = {
[propName + 'Label']: 'Size',
['get' + propName]() {
return this[propName];
},
set [propName](value) {
this._size = value;
},
get [propName]() {
return this._size;
}
};
console.log(obj.sizeLabel); // 输出:Size
obj.size = 10;
console.log(obj.getSize()); // 输出:10
在上面的例子中,我们在对象字面量中使用了计算属性名的语法,将变量 propName
和字符串 'Label'
进行了拼接,并且作为了一个属性名。同时,我们也定义了一个计算属性 size
,并且使用 get
和 set
关键字来定义了该属性的读取和修改方法。
八、扩展运算符
ES6 中的扩展运算符用三个连续的点 ...
表示,主要用于将一个可迭代对象(如数组、字符串或类数组对象)展开成多个元素
1、数组的展开
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combinedArray = [...arr1, ...arr2];
console.log(combinedArray); // 输出:[1, 2, 3, 4, 5, 6]
在上面的例子中,我们使用扩展运算符将两个数组 arr1
和 arr2
展开,并且合并成一个新的数组 combinedArray
。
2、字符串的展开
const str = 'hello';
const chars = [...str];
console.log(chars); // 输出:['h', 'e', 'l', 'l', 'o']
在上面的例子中,我们使用扩展运算符将字符串 str
展开成一个字符数组 chars
,每个字符都成为了数组的一个元素。
3、函数的参数传递
function sum(a, b, c) {
return a + b + c;
}
const numbers = [1, 2, 3];
const result = sum(...numbers);
console.log(result); // 输出:6
在上面的例子中,我们定义了一个求和函数 sum()
,并且使用扩展运算符将数组 numbers
的元素作为函数的参数进行传递。
4、对象的展开
const obj1 = { foo: 'bar' };
const obj2 = { baz: 'qux' };
const mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj); // 输出:{ foo: 'bar', baz: 'qux' }
在上面的例子中,我们使用扩展运算符将两个对象 obj1
和 obj2
的属性展开,并且合并成一个新的对象 mergedObj
。
扩展运算符不仅可以用于数组、字符串、对象的展开,还可以用于函数调用时的参数展开等场景,能够让我们更方便地处理和操作数据。
九、模块化导入和导出
当使用模块化导入和导出时,可以将 JavaScript 代码分割为多个模块,每个模块负责封装和导出特定的功能,然后在其他模块中导入并使用这些功能。这种模块化的方式有助于提高代码的可维护性和可重用性。
假设我们有一个名为 math.js
的模块,其中定义了一些数学相关的函数:
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
export const PI = 3.14159;
在另一个模块中,我们可以使用 import
关键字导入 math.js
模块中的函数和变量:
// app.js
import { add, subtract, PI } from './math.js';
console.log(add(2, 3)); // 输出:5
console.log(subtract(7, 4)); // 输出:3
console.log(PI); // 输出:3.14159
我们使用 import
关键字从 math.js
模块中导入 add
、subtract
函数和 PI
变量。然后,在 app.js
模块中,我们可以像使用本地函数和变量一样使用它们。
除了按需导入特定函数和变量外,还可以使用 import * as
语法导入整个模块的所有导出:
// app.js
import * as math from './math.js';
console.log(math.add(2, 3)); // 输出:5
console.log(math.subtract(7, 4)); // 输出:3
console.log(math.PI); // 输出:3.14159
我们使用 import * as
将整个 math.js
模块导入为 math
对象。然后,我们可以通过该对象访问模块中的所有导出。
十、数组新增方法
ES6 在数组原型上新增了一些方法,如 find、findIndex、includes 等,方便对数组进行查找和操作
1、Array.prototype.find()
find()
方法返回数组中满足指定条件的第一个元素。如果找到了符合条件的元素,则返回该元素;否则返回 undefined。
const arr = [1, 2, 3, 4, 5];
// 查找数组中第一个大于等于 3 的元素
const result = arr.find(item => item >= 3);
console.log(result); // 输出:3
2、Array.prototype.findIndex()
findIndex()
方法返回数组中满足指定条件的第一个元素的索引。如果找到了符合条件的元素,则返回该元素的索引;否则返回 -1。
const arr = [1, 2, 3, 4, 5];
// 查找数组中第一个大于等于 3 的元素的索引
const index = arr.findIndex(item => item >= 3);
console.log(index); // 输出:2
3、Array.prototype.includes()
includes()
方法判断数组中是否包含指定元素,如果包含则返回 true;否则返回 false。
const arr = [1, 2, 3, 4, 5];
// 判断数组中是否包含 3
const isIncluded = arr.includes(3);
console.log(isIncluded); // 输出:true
4、Array.prototype.fill()
fill()
方法用指定的值填充数组中的所有元素。
const arr = [1, 2, 3, 4, 5];
// 将数组中所有元素都填充为 0
arr.fill(0);
console.log(arr); // 输出:[0, 0, 0, 0, 0]
5、Array.prototype.flat()
flat()
方法将多维数组扁平化为一维数组。
const arr = [1, [2, [3, [4, 5]]]];
// 扁平化数组
const flatArr = arr.flat();
console.log(flatArr); // 输出:[1, 2, 3, 4, 5]
十一、迭代器和生成器
ES6 引入了迭代器和生成器的概念,通过 Symbol.iterator 和 function*关键字可以创建可迭代对象和生成器函数,用于更灵活地进行迭代操作。
1、迭代器
迭代器是一种特殊对象,可以用来遍历集合中的元素。在 JavaScript 中,一个对象如果具有 Symbol.iterator
属性并且该属性是一个函数,则称该对象为可迭代对象,并且可以使用 for...of
循环或者 ...
运算符对其进行遍历。
const myIterator = {
data: [1, 2, 3],
[Symbol.iterator]() {
let index = 0;
return {
next: () => {
if (index < this.data.length) {
return { value: this.data[index++], done: false };
} else {
return { done: true };
}
}
};
}
};
for (let item of myIterator) {
console.log(item);
}
// 输出:1 2 3
我们定义了一个自定义迭代器 myIterator,它包含一个数组 data 和一个 Symbol.iterator 属性,该属性返回一个迭代器对象。该迭代器对象包含一个 next() 方法,每次调用 next() 方法都会返回一个包含 value 和 done 两个属性的对象。
2、生成器
生成器是一种特殊的函数,可以通过 function*
关键字来定义。生成器函数执行时不会立即执行函数体,而是返回一个迭代器对象,通过迭代器对象可以逐步执行函数体,并返回多个值。
function* myGenerator() {
yield 1;
yield 2;
yield 3;
}
const generator = myGenerator();
console.log(generator.next()); // 输出:{ value: 1, done: false }
console.log(generator.next()); // 输出:{ value: 2, done: false }
console.log(generator.next()); // 输出:{ value: 3, done: false }
console.log(generator.next()); // 输出:{ done: true }
我们定义了一个生成器函数 myGenerator
,它包含三个 yield
表达式。我们通过调用该函数得到一个迭代器对象 generator
,每次调用 generator.next()
都会执行一次函数体,并返回一个包含 value
和 done
两个属性的对象。当函数执行完毕时,done
属性为 true
。
十二、类和继承
ES6 引入了类的概念,更贴近传统面向对象编程的语法。
在 JavaScript 中,是通过构造函数来生成实例对象。
function A(a){
this.a=a
}
A.prototype.sayA=function(){
console.log(this.a)
}
var a=new A('a')
a.sayA()
在ES6中引入了 class(类)的概念,通过class
关键字可以定义类。这种写法使得对象原型的写法更加清晰、更像面对对象编程的语法了。
class A{
// constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
constructor(a){
this.a=a
}
sayA(){
console.log(this.a)
}
}
var a=new A('a')
a.sayA()
在定义类的方法时,不需要加上 function 关键字,使用的时候也是直接对类进行new
命令,跟构造函数是一样的。
构造函数的prototype
属性,在 ES6 的类中继续存在,类的所有方法都定义在类的prototype
属性上面。
class A{
constructor(){
}
sayA(){}
sayB(){}
}
相当于
A.prototype={
sayA(){},
sayB(){}
}
十三、Map和Set
提供了更方便的键值对集合和无重复值的集合。
const map = new Map();
map.set('key', 'value');
const set = new Set([1, 2, 3]);
本文转载自:ES6 语法详解+面试必备
提醒:本文发布于129天前,文中所关联的信息可能已发生改变,请知悉!
Tips:清朝云网络工作室