更多详细可以查看1.1 ES6 教程 | 菜鸟教程
这里我将大概记录ES与JS大概不一样的部分,方便联合记忆。
历史与关系
- ECMAScript:是一种由 Ecma 国际组织制定的脚本语言规范,它是 JavaScript 的标准化版本。ECMAScript 为 JavaScript 提供了语法、类型、语句、关键字等基础规范,随着时间推移不断发展和更新版本。
- JavaScript:是一种广泛应用于网页开发等领域的编程语言,它遵循 ECMAScript 规范,并由各大浏览器厂商进行实现和扩展。除了 ECMAScript 规定的核心特性外,JavaScript 还包括宿主环境(如浏览器)提供的 API,如 DOM、BOM 等。
变量声明
- JS(ES5 及以前):使用
var
声明变量,存在变量提升现象,即变量可以在声明之前使用,其作用域为函数级作用域。例如:
function test() {console.log(x); // 输出undefinedvar x = 10;
}
test();
- ES6:引入了
let
和const
。let
声明的变量具有块级作用域,不存在变量提升,在声明之前访问会报错,称为 “暂时性死区”。const
用于声明常量,一旦声明,不可重新赋值,且也具有块级作用域,当然,仅在一个代码块内的声明let和const变量,仅在代码块内有效。例如:
{let y = 20;const z = 30;
}
console.log(y); // 报错,y is not defined
console.log(z); // 报错,z is not defined
传统 JavaScript 使用var
声明变量,存在函数级作用域和变量提升现象。例如,var
声明的变量可以在声明之前被访问,值为undefined
,而let
和const
声明的变量不存在变量提升,在声明之前访问会报错。
函数
- JS(ES5 及以前):函数声明有函数声明语句和函数表达式两种方式,
this
指向在运行时根据函数的调用方式确定,在全局函数中,this
指向全局对象(浏览器中是window
),在对象方法中,this
指向调用该方法的对象。例如:
function add(a, b) {return a + b;
}
const subtract = function (a, b) {return a - b;
};
- ES6:引入了箭头函数,语法为
(param1, param2, ...) => { function body },
箭头函数没有自己的this
,它的this
继承自外层作用域,更适合用于回调函数等场景,避免了this
指向不明确的问题。例如:
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map((num) => num * 2);
与传统的function
关键字定义的函数相比,箭头函数没有自己的this
绑定,它的this
指向定义时所在的外层作用域,避免了一些常见的this
指向问题。
数组
- JS(ES5 及以前):有
push
、pop
、shift
、unshift
等方法用于操作数组。例如:
const arr = [1, 2, 3];
arr.push(4);
arr.shift();
- ES6:增加了
find
、findIndex
、includes
等方法。find
用于找到数组中满足条件的第一个元素,findIndex
用于找到满足条件的第一个元素的索引,includes
用于判断数组是否包含某个元素。例如:
const numbers = [1, 2, 3, 4, 5];
const found = numbers.find((num) => num > 3);
const index = numbers.findIndex((num) => num === 4);
const hasFive = numbers.includes(5);
对象
- JS(ES5 及以前):通过对象字面量或构造函数创建对象,使用点语法或方括号语法访问属性。例如:
const person = {name: 'John',age: 30
};
console.log(person.name);
console.log(person['age']);
- ES6:允许对象属性的简洁表示法,即属性名和变量名相同时可以简写。还增加了
Object.assign
方法用于对象的合并,Object.keys
、Object.values
、Object.entries
方法用于获取对象的键、值和键值对数组。例如:
const name = 'Alice';
const age = 25;
const person = { name, age }; // 简洁表示法
const obj1 = { a: 1 };
const obj2 = { b: 2 };
const merged = Object.assign({}, obj1, obj2);
const keys = Object.keys(person);
const values = Object.values(person);
const entries = Object.entries(person);
模块
- JS(ES5 及以前):没有原生的模块系统,通常使用第三方库如
RequireJS
等来实现模块加载。 - ES6:引入了原生的模块系统,使用
import
和export
关键字来导入和导出模块。例如:
// 定义模块 math.js
export function add(a, b) {return a + b;
}
export function subtract(a, b) {return a - b;
}
import { add, subtract } from './math.js';
console.log(add(5, 3));
console.log(subtract(5, 3));
字符串
- JS(ES5 及以前):有
charAt
、indexOf
、substring
等方法操作字符串。
const str = 'Hello, World!';
console.log(str.charAt(0));
console.log(str.indexOf('World'));
console.log(str.substring(7, 12));
- ES6:增加了
includes
、startsWith
、endsWith
等方法,用于更方便地判断字符串是否包含某个子串、是否以某个子串开头或结尾。
const str = 'Hello, World!';
console.log(str.includes('World'));
console.log(str.startsWith('Hello'));
console.log(str.endsWith('!'));
数据类型与结构
- Symbol 类型
- 一种新的数据类型,
Symbol
值是唯一的、不可变的,常用于创建对象的唯一属性键,避免属性名冲突。 - 在 ES6 之前,JavaScript 的基本数据类型只有
number
、string
、boolean
、null
、undefined
,Symbol
的引入为对象属性的管理提供了更强大的方式。
let sy = Symbol("KK");
console.log(sy); // Symbol(KK)
typeof(sy); // "symbol"// 相同参数 Symbol() 返回的值不相等
let sy1 = Symbol("kk");
sy === sy1; // false
- 解构赋值
- 可以方便地从数组或对象中提取值,并赋值给多个变量。例如,
const [a, b, c] = [1, 2, 3]
可以将数组中的值分别赋给a
、b
、c
;const { name, age } = { name: 'John', age: 30 }
可以从对象中提取name
和age
属性并赋值给同名变量。 - 传统的赋值方式需要逐个进行赋值操作,解构赋值更加简洁和直观,提高了代码的可读性和便利性,尤其在处理函数返回多个值或对象属性较多的情况时优势明显。
面向对象编程
- 类的语法
- 使用
class
关键字来定义类,包括构造函数、实例方法和静态方法等。
- 使用
class Person {constructor(name, age) {this.name = name;this.age = age;}sayHello() {console.log(`Hello, my name is ${this.name}`);}static createPerson(name, age) {return new Person(name, age);}
}
在 ES6 之前,JavaScript 通过构造函数和原型链来模拟类和继承,代码结构相对复杂且不直观。class
语法使 JavaScript 的面向对象编程更加清晰和易于理解,与其他面向对象编程语言的语法更加相似。
- 继承:使用
extends
关键字实现类的继承,super
关键字用于调用父类的构造函数和方法。
class Student extends Person {constructor(name, age, grade) {super(name, age);this.grade = grade;}sayHello() {super.sayHello();console.log(`I'm in grade ${this.grade}`);}
}
ES6 之前的继承实现需要手动操作原型链,容易出现一些问题,如原型链混乱、子类实例无法正确访问父类属性等。extends
和super
的使用使继承的实现更加规范和可靠。
异步编程
- Promise是一种用于处理异步操作的对象,它代表了一个异步操作的最终完成(或失败)及其结果值。可以使用
then
方法来处理成功的结果,catch
方法来处理失败的情况。 - 在 Promise 出现之前,JavaScript 的异步操作通常使用回调函数来处理,但回调函数容易导致回调地狱,即多层嵌套的回调函数使代码难以阅读和维护。Promise 通过链式调用的方式使异步操作的代码更加清晰和易于管理。
- async/await
- ES7 引入:基于 Promise 之上的异步函数语法,
async
函数返回一个 Promise 对象,await
只能在async
函数内部使用,用于暂停函数执行,等待 Promise 被解决(resolved)或被拒绝(rejected)。 - 与 Promise 的
then
链式调用相比,async/await
使异步代码看起来更像同步代码,大大提高了异步代码的可读性和可维护性,减少了异步操作带来的复杂性。
- ES7 引入:基于 Promise 之上的异步函数语法,
模块系统
- ES6 模块
- ES6 引入:使用
import
和export
关键字来实现模块的导入和导出。可以将不同的功能封装在不同的模块中,通过export
暴露需要对外提供的变量、函数、类等,通过import
在其他模块中引入这些内容。 - 在 ES6 之前,JavaScript 没有官方的模块系统,开发者通常使用各种第三方库(如 CommonJS、AMD 等)来实现模块功能。ES6 模块系统提供了标准化的模块定义和加载方式,使代码的组织和管理更加规范和高效。
- ES6 引入:使用
(未完待续)
这些 ES 的特性极大地丰富和增强了 JavaScript 的功能和表现力,使开发者能够更方便、高效地编写复杂的前端应用程序。在学习和使用 JavaScript 时,掌握这些 ES 的重要特性是非常关键的。