ECMAScript6
ES6 简介
ECMAScript6,简称 ES6,是 JavaScript 语言的一次重大更新。它于 2015 年发布,是原来的 ECMAScript 标准的第六个版本。ES6 带来了大量的新特性,包括箭头函数、模板字符串、let 和 const 关键字、解构、默认参数值、模块系统等等,大大提升了 JavaScript 的开发体验。
由于 vUE3 中大量使用了 ES6 的语法,所以 ES6 成为了学习 VUE3 的门槛之一。
ES6 对 JavaScript 的改进在以下几个方面:
- 更加简洁:ES6 引入了一些新的语法,如箭头函数、类和模板字符串等,使代码更加简洁易懂
- 更强大的功能:ES6 引入了一些新的 API、解构语法和迭代器等功能,从而使得 JavaScript 更加强大
- 更好的适用性:ES6 引入的模块化功能为 JavaScript 代码的组织和管理提供了更好的方式,不仅提高了程序的可维护性,还让 JavaScript 更方便地应用于大型的应用程序
ES6 变量
ES6 新增了 let 和 const,用来声明变量,使用的细节上也存在诸多差异
let 和 var 的差别:
- let 不能重复声明;
- let 有块级作用域,非函数的花括号遇见 let 会有块级作用域,也就是只能在花括号里面访问;
- let 不会预解析进行变量提升;
- let 定义的全局变量不会作为 window 的属性;
- let 在 es6 中推荐优先使用;
const 和 var 的差异:
- 新增 const 和 let 类似,只是 const 定义的变量不能修改;
- 并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动;
// var 具有函数级作用域
// 重复声明
var avar = 1;
var avar = 2; // 2
// 变量提升
console.log(bvar); // 1
var bvar = 1;
// 会成为window对象的属性
console.log(window.avar); // 2
// let
// 不能重复声明
let alet = 1;
// let alet = 2; // SyntaxError: Identifier 'alet' has already been declared
// 具有块级作用域
{
let blet = 3;
console.log(blet); // 3
}
// console.log(blet); // ReferenceError: blet is not defined
// 不存在变量提升
// console.log(clet); // ReferenceError: Cannot access 'clet' before initialization
let clet = 4;
console.log(clet);
// 不会成为window对象的属性
console.log(window.alet); // undefined
// const
// 不能重新赋值
const aconst = 5;
// aconst = 6; // TypeError: Assignment to constant variable.
// 具有块级作用域
{
const bconst = 7;
console.log(bconst); // 7
}
// console.log(bconst); // ReferenceError: bconst is not defined
// 数组或对象 可以修改内容但不能重新赋值 即引用地址不能变
const arr = [1, 2, 3];
arr.push(4); // 可以修改数组内容
console.log(arr); // [1, 2, 3, 4]
const obj = { name: 'Alice' };
obj.name = 'Bob'; // 可以修改对象属性
console.log(obj); // { name: 'Bob' }ES6 模板字符串
模板字符串(template string)是增强版的字符串,用反引号 ` 标识
- 字符串中可以出现换行符;
- 可以使用
${xxx}形式输出变量和拼接变量;
// 模板字符串
let item1 = 'Item 1';
let item2 = 'Item 2';
let item3 = 'Item 3';
let item4 = 'Item 4';
let str = "<ul>\n" +
" <li>" + item1 + "</li>\n" +
" <li>" + item2 + "</li>\n" +
" <li>" + item3 + "</li>\n" +
" <li>" + item4 + "</li>\n" +
"</ul>";
console.log(str);
let templateStr = `<ul>
<li>${item1}</li>
<li>${item2}</li>
<li>${item3}</li>
<li>${item4}</li>
</ul>
`;
console.log(templateStr);ES6 解构表达式
ES6 的解构赋值是一种方便的语法,可以快速将数组或对象中的值拆分并赋值给变量。解构赋值的语法使用花括号 {} 表示对象,方括号 [] 表示数组。通过解构赋值,函数更方便进行参数接受等!
// 数组解构
let arr = [1, 2, 3];
let [a, b, c, d=10] = arr;
console.log(a, b, c, d); // 1 2 3 10
// 对象解构
let person = { name: 'Alice', age: 30 };
let { name1, age1 } = person;
console.log(name1, age1); // undefined undefined
let { age , name } = person;
console.log(name, age); // Alice 30
let {name: name2, age: age2} = person;
console.log(name2, age2); // Alice 30
// 参数列表解构
function showArray([x, y, z=20]) {
console.log(`x: ${x}, y: ${y}, z: ${z}`);
}
showArray([5, 10]); // x: 5, y: 10
function greet({ name, age }) {
console.log(`Hello, ${name}! You are ${age} years old.`);
}
greet(person); // Hello, Alice! You are 30 years old.ES6 的箭头函数
ES6 允许使用“箭头”义函数。语法类似 Java 中的 Lambda 表达式。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 箭头函数
let func1 = function() {};
let func2 = () => {};
let func3 = (x, y) => { console.log(x, y); return x + y; };
let func4 = (x, y) => console.log(x, y); // 只有一个表达式时 可以省略大括号
let func5 = x => console.log(x); // 只有一个参数时 可以省略括号
let func6 = (x , y) => x + y; // 仅仅return 一个表达式时,可以省略大括号和 return 关键字
// 普通函数的 this 是调用时确定的,箭头函数的 this 是定义时确定的。
// 箭头函数 没有自己的 this,this 的值是外层作用域的 this 的值,在定义时就确定了。
let obj = {
name: 'Alice',
regularFunc: function() {
console.log(this); // 指向 obj
console.log(this.name); // Alice
},
arrowFunc: () => {
console.log(this); // 指向全局对象 window
console.log(this.name); // ''
}
};
obj.regularFunc();
obj.arrowFunc();
window.onload = function() {
// 这使得箭头函数非常适合用作回调函数,尤其是在需要访问外层 this 的时候。
var div1 = document.getElementById('div1');
div1.onclick = function(){
// this 指向 div1 可用于操作div1的样式
console.log(this); // div1
this.style.backgroundColor = 'lightcoral'; // this 指向 div1
setTimeout(function() {
// 因为 setTimeout 属于window对象(全局函数) 所以这里的 this 指向全局对象 window
console.log(this); // window
// this.style.backgroundColor = 'lightblue'; // this 指向 window 无法操作 div1 的样式
}, 1000);
setTimeout(() => {
this.style.backgroundColor = 'lightblue'; // this 指向 div1 可以操作 div1 的样式
}, 2000);
};
};
</script>
<style>
#div1 {
width: 100px;
height: 100px;
background-color: lightblue;
}
</style>
</head>
<body>
<div id="div1"></div>
</body>
</html>ES6 rest 参数 和 spread 展开
// rest 形参
let func1 = function(a, b, c, d, ...args) {
console.log(a, b, c, d);
console.log(args);
};
func1(1, 2, 3, 4, 5, 6, 7);
// spread 实参数组展开
let arr = [1, 2, 3];
let func2 = function(x, y, z) {
console.log(x, y, z);
};
func2(arr); // 1 undefined undefined
func2(...arr); // 1 2 3
let func3 = function([x, y, z]) {
console.log(x, y, z);
};
func3(arr); // 1 2 3
// func3(...arr); // number 1 is not iterable (cannot read property Symbol(Symbol.iterator))
// spread 数组合并
let arr1 = [1, 2];
let arr2 = [3, 4];
let mergedArr = [...arr1, ...arr2];
console.log(mergedArr); // [1, 2, 3, 4]
// spread 对象合并
let obj1 = { name: 'Alice', age: 30 };
let obj2 = { city: 'New York', country: 'USA' };
let mergedObj = { ...obj1, ...obj2 };
console.log(mergedObj); // { name: 'Alice', age: 30, city: 'New York', country: 'USA' }ES6 对象创建和拷贝
ES6 中新增了对象创建的语法糖,支持了 class extends constructor 等关键字,让 ES6 的语法和面向对象的语法更加接近。
浅拷贝和深拷贝
// 浅拷贝
let arr1 = [1, 2, 3];
let arr2 = arr1; // 直接赋值,arr2引用了arr1的内存地址
arr1[0] = 10;
console.log(arr2); // [10, 2, 3]
// 深拷贝
let arr3 = [1, 2, 3];
let arr4 = [...arr3]; // 使用扩展运算符创建新数组
arr3[0] = 10;
console.log(arr4); // [1, 2, 3]
let obj1 = { name: 'Alice', age: 30 };
let obj2 = { ...obj1 }; // 使用扩展运算符创建新对象
obj1.name = 'Bob';
console.log(obj2); // { name: 'Alice', age: 30 }
let obj3 = JSON.parse(JSON.stringify(obj1)); // 使用 JSON 方法进行深拷贝
obj1.name = 'Charlie';
console.log(obj3); // { name: 'Bob', age: 30 }ES6 模块化处理
模块化是一种组织和管理前端代码的方式,将代码拆分成小的模块单元,使得代码更易于维护,扩展和复用。它包括了定义、导出、导入以及管理模块的方法和规范。
前端模块化的主要优势如下:
- 提高代码可维护性:通过将代码拆分为小的模块单元,使得代码结构更为清晰,可读性更高,便于开发者阅读和维护;
- 提高代码可复用性:通过将重复使用的代码变成可复用的模块,减少代码重复率,降低开发成本;
- 提高代码可扩展性:通过模块化来实现代码的松耦合,便于更改和替换模块,从而方便地扩展功能;
目前,前端模块化有多种规范和实现,包括 CommonJS、AMD 和 ES6 模块化。ES6 模块化是 JavaScript 语言的模块标准,使用 import 和 export 关键字来实现模块的导入和导出。现在,大部分浏览器都已经原生支持 ES6 模块化,因此它成为了最为广泛使用的前端模块化标准.。
开启支持
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- type = "module" 使浏览器支持 ES6 模块化管理-->
<script type="module" src="./modules/app.js"></script>
</head>
<body>
</body>
</html>ES6 模块化的暴露方式:
分别导出;
js// module1.js // 分别暴露 export const PI = 3.1415926; const E = 2.718281828; export function area(r) { return PI * r * r; }统一导出;
js// module2.js // 统一暴露 const PI = 3.1415926; const E = 2.718281828; function area(r) { return PI * r * r; } export { E, area };默认导出;
js// 默认暴露 const PI = 3.1415926; const E = 2.718281828; function area(r) { return PI * r * r; } // export default 只能有一个 // 假设默认暴露一个 export default { PI }; // 全暴露 export { PI, E, area };
ES6 中无论以何种方式导出,导出的都是一个对象,导出的内容都可以理解为是向这个对象中添加属性或者方法!!!
导入
// 导入模块的所有暴露
import * as module1 from './module1.js';
console.log(module1.PI);
console.log(module1.E); // undefined
console.log(module1.area(2));
// 解构赋值导入模块的部分暴露
import { E, area } from './module2.js';
console.log(E);
console.log(area(2));
// 导入模块的默认暴露
import module3 from './module3.js';
console.log(module3.PI); // 可导出
console.log(module3.E); // undefined
console.log(module3.area(2)); // not a function