外观
外观
耶温
5589字约19分钟
2024-05-11
ECMAScript(简称 ES)是一种由 ECMA 国际组织制定的脚本语言标准。它是 JavaScript 的基础,定义了语言的语法、类型、语句、关键字、保留字、操作符、内置对象等。ECMAScript 的目标是提供一种通用的脚本语言,使得不同的实现(如浏览器、服务器等)能够遵循相同的标准,从而实现跨平台的兼容性。
let:用于声明块级作用域的变量,避免了使用 var 声明变量时可能出现的作用域问题。
let
声明的变量具有块级作用域,即它只在其所在的代码块内有效。{
let x = 10;
console.log(x); // 10
}
console.log(x); // ReferenceError: x is not defined
let
重复声明同一个变量。let y = 20;
let y = 30; // SyntaxError: Identifier 'y' has already been declared
let
声明的变量会被提升,但在声明之前访问会导致 ReferenceError
,这被称为“暂时性死区”(Temporal Dead Zone)。console.log(z); // ReferenceError: Cannot access 'z' before initialization
let z = 30;
const:用于声明常量,常量的值不能被重新赋值,且同样具有块级作用域。
{
const a = 5;
console.log(a); // 5
}
console.log(a); // ReferenceError: a is not defined
const b = 10;
// b = 20; // TypeError: Assignment to constant variable.
const obj = { name: 'Alice' };
obj.name = 'Bob'; // 允许,内容可变
console.log(obj.name); // Bob
// obj = {}; // TypeError: Assignment to constant variable.
const c = 15;
const c = 25; // SyntaxError: Identifier 'c' has already been declared
需要注意的是,虽然 const 定义的变量,不允许重新进行复制。但是对于复杂类型的数据来说,const 只能保证变量指向的内存地址不会改变,不会影响指向的数据是不是可变的。可以通过Object.freeze()
方法冻结对象。
Object.freeze()
可以冻结一个对象,对象不能再被修改,添加和删除
箭头函数(Arrow Functions)是 ECMAScript 6(ES6)引入的一种新的函数表达式语法。它提供了一种更简洁的方式来定义函数,并且在处理 this 关键字时具有不同的行为。
基本语法
const functionName = (parameters) => {
// function body
};
const sum = (a, b) => a + b;
console.log(sum(1, 2)); // 3
const greet = () => 'Hello, World!';
console.log(greet()); // Hello, World!
const square = x => x * x;
console.log(square(4)); // 16
const multiply = (a, b) => {
const result = a * b;
return result;
};
console.log(multiply(2, 5)); // 10
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8]
应用场景
const numbers = [1, 2, 3, 4];
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8]
const even = numbers.filter(num => num % 2 === 0);
console.log(even); // [2, 4]
const sum = numbers.reduce((acc, num) => acc + num, 0);
console.log(sum); // 10
const button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log('Button clicked');
});
const users = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 35 }
];
users.forEach(user => {
console.log(`${user.name} is ${user.age} years old.`);
});
注意事项
const person = {
name: 'John',
age: 30,
greet: function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
};
const greet = () => {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
person.greet(); // Hello, my name is John and I am 30 years old.
greet(); // Hello, my name is undefined and I am undefined years old.
const Person = (name, age) => {
this.name = name;
this.age = age;
};
const john = new Person('John', 30); // TypeError: Person is not a constructor
const sum = (a, b) => {
console.log(arguments); // ReferenceError: arguments is not defined
return a + b;
};
const generator = () => {
yield 1;
yield 2;
};
const gen = generator();
gen.next(); // TypeError: generator is not a generator function
模板字符串(Template Literals)是 ECMAScript 6(ES6)引入的一种新的字符串表示法,它使用反引号(`)来定义字符串,提供了更强大的功能。
const multiLineString = `这是一个
多行字符串`;
console.log(multiLineString);
${}
语法将变量或表达式的值插入到字符串中。const name = 'Alice';
const greeting = `Hello, ${name}!`;
console.log(greeting); // Hello, Alice!
${}
语法将表达式的值插入到字符串中。const a = 5;
const b = 10;
const result = `5 + 10 = ${a + b}`;
console.log(result); // 输出: 5 + 10 = 15
function tag(strings,...values) {
let result = '';
for (let i = 0; i < strings.length; i++) {
result += strings[i];
if (i < values.length) {
result += values[i];
}
}
return result;
}
const result = tag`Hello, ${name}!`;
console.log(result); // Hello, Alice!
const quote = `他说: "你好,世界!"`;
console.log(quote); // 输出: 他说: "你好,世界!"
const name = 'Alice';
const greeting = `Hello, \'${name}\'!`;
console.log(greeting); // Hello, 'Alice'!
解构赋值语法是一种 Javascript 表达式。通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。
const numbers = [1, 2, 3, 4, 5];
const [first, second,...rest] = numbers;
console.log(first, second, rest); // 1 2 [3, 4, 5]
解构时忽略某些数组元素。
const array = [1, 2, 3];
const [a, , c] = array;
console.log(a); // 输出: 1
console.log(c); // 输出: 3
解构时给变量设置默认值。
const array = [1];
const [a, b = 2] = array;
console.log(a); // 输出: 1
console.log(b); // 输出: 2
const person = {
name: 'Alice',
age: 25
};
const { name, age } = person;
console.log(name, age); // Alice 25
解构时重命名变量。
const person = {
name: 'Alice',
age: 25
};
const { name: myName, age: myAge } = person;
console.log(myName, myAge); // Alice 25
const person = {
name: 'Alice',
age: 25,
address: {
city: 'New York',
country: 'USA'
}
};
const { address: { city } } = person;
console.log(city); // New York
function greet({ name = 'Guest', age = 0 }) {
console.log(`Hello, ${name}! You are ${age} years old.`);
}
greet({ name: 'Bob', age: 30 }); // Hello, Bob! You are 30 years old.
greet({ name: 'Charlie' }); // Hello, Charlie! You are 0 years old.
总的来说,解构赋值提供了一种简洁的方式来提取数组和对象中的值,减少了代码的冗余,提高了可读性。它在现代 JavaScript 开发中得到了广泛的应用,尤其是在处理复杂数据结构时。
扩展运算符(Spread Operator)是 ECMAScript 6(ES6)引入的一种语法,使用三个点(...)表示。它可以将可迭代对象(如数组、字符串、对象等)展开为个别元素或属性。
// 合并数组
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const mergedArray = [...array1,...array2];
console.log(mergedArray); // [1, 2, 3, 4, 5, 6]
// 复制数组
const array3 = [...array1];
console.log(array3); // [1, 2, 3]
// 添加元素
const array4 = [...array1, 4];
console.log(array4); // [1, 2, 3, 4]
// 复制对象
const object1 = { name: 'Alice', age: 25 };
const object2 = {...object1};
console.log(object2); // { name: 'Alice', age: 25 }
// 添加或覆盖属性
const object3 = {...object1, address: 'New York'};
console.log(object3); // { name: 'Alice', age: 25, address: 'New York' }
扩展运算符可以将字符串转换为数组。
// 分割字符串
const str = 'Hello, World!';
const chars = [...str];
console.log(chars); // ['H', 'e', 'l', 'l', 'o', ',','', 'W', 'o', 'r', 'l', 'd', '!']
const numbers = [1, 2, 3];
const sum = (a, b, c) => a + b + c;
console.log(sum(...numbers)); // 输出: 6
扩展运算符与剩余参数(Rest Parameters)相对,后者用于将函数的多个参数收集到一个数组中。
const sum = (...args) => {
return args.reduce((acc, curr) => acc + curr, 0);
};
console.log(sum(1, 2, 3, 4)); // 输出: 10
总体来说,扩展运算符是一种非常有用的语法,可以简化代码,提高可读性和可维护性。它在现代 JavaScript 开发中广泛应用,特别是在处理数组、对象、字符串和函数参数时。
ECMAScript 6(ES6)引入了类(Class)的概念,使得 JavaScript 的面向对象编程更加清晰和易于使用。类是构造函数的语法糖,提供了一种更直观的方式来创建对象和处理继承。
基本语法
class ClassName {
constructor(parameters) {
// 构造函数
}
methodName() {
// 方法
}
}
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
}
const person = new Person('Alice', 25);
person.sayHello(); // Hello, my name is Alice and I am 25 years old.
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
sayGrade() {
console.log(`I am in grade ${this.grade}.`);
}
}
const student = new Student('Bob', 20, 'A');
student.sayHello(); // Hello, my name is Bob and I am 20 years old.
student.sayGrade(); // I am in grade A.
class MathUtils {
static PI = 3.14159;
static square(x) {
return x * x;
}
}
console.log(MathUtils.PI); // 输出: 3.14159
console.log(MathUtils.square(5)); // 输出: 25
class Person {
#name;
#age;
constructor(name, age) {
this.#name = name;
this.#age = age;
}
#sayHello() {
console.log(`Hello, my name is ${this.#name} and I am ${this.#age} years old.`);
}
sayHello() {
this.#sayHello();
}
}
const person = new Person('Alice', 25);
person.sayHello(); // Hello, my name is Alice and I am 25 years old.
// console.log(person.#name); // 报错: #name 是私有的属性
ECMAScript 模块(ES Modules)是 ECMAScript 6(ES6)引入的一种模块化机制,旨在使 JavaScript 代码的组织和管理更加清晰和高效。ES 模块允许开发者将代码分割成多个文件,并在这些文件之间进行导入和导出,从而实现代码的重用和维护。
基本概念
export
关键字将模块中的变量、函数或类导出,使其可以在其他模块中使用。import
关键字从其他模块中导入导出的内容。导出模块
// 默认导出
export default function greet(name) {
console.log(`Hello, ${name}`);
}
export
关键字。// 命名导出
// myModule.js
export const name = 'Alice';
export const age = 25;
export function greet() {
console.log(`Hello, ${name}`);
}
导入模块
import
关键字导入默认导出的内容。// 默认导入
import greet from './myModule.js';
greet('Alice'); // Hello, Alice
import
关键字导入命名导出的内容。// 命名导入
import { name, age, greet } from './myModule.js';
console.log(name); // Alice
console.log(age); // 25
greet(); // Hello, Alice
as
关键字重命名导入的变量、函数或类。// 重命名导入
import { name as myName, age as myAge } from './myModule.js';
console.log(myName); // Alice
console.log(myAge); // 25
*
导入模块中的所有内容。// 导入全部
import * as myModule from './myModule.js';
console.log(myModule.name); // Alice
console.log(myModule.age); // 25
myModule.greet(); // Hello, Alice
注意事项
<script>
标签中添加 type="module"
属性。动态导入 可以使用 import()
函数动态导入模块,返回一个 Promise。
async function loadModule() {
const module = await import('./myModule.js');
console.log(module.name); // Alice
}
loadModule();
Promise 是 ECMAScript 6(ES6)引入的一种用于处理异步操作的对象。它代表一个可能在未来某个时间点完成或失败的操作,并允许你以更清晰的方式处理异步代码,避免了回调地狱(callback hell)的问题。
提示
关于 Promise 的详细内容可以查看:JavaScript-Promise
在 ECMAScript 6(ES6)中,生成器(Generators)和迭代器(Iterators)是用于处理可迭代对象的重要概念。它们使得在 JavaScript 中处理序列数据变得更加灵活和强大。
迭代器(Iterator) 迭代器是一种对象,它定义了访问集合中元素的方式。迭代器必须实现一个 next() 方法,该方法返回一个对象,该对象包含两个属性:
done
:一个布尔值,表示迭代是否完成。value
:迭代返回的值。function createIterator(array) {
let index = 0;
return {
next: function() {
if (index < array.length) {
return { value: array[index++], done: false };
} else {
return { done: true };
}
}
};
}
const iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // { value: 1, done: false }
console.log(iterator.next()); // { value: 2, done: false }
console.log(iterator.next()); // { value: 3, done: false }
console.log(iterator.next()); // { done: true }
生成器(Generator)
生成器是一种特殊类型的函数,可以暂停和恢复执行。生成器函数使用 function* 语法定义,并且可以使用 yield
关键字来返回值。每次调用生成器的 next()
方法时,生成器会执行到下一个 yield
表达式,并返回一个对象,包含 value
和 done
属性。
function* createGenerator() {
yield 1;
yield 2;
yield 3;
}
const generator = createGenerator();
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 }
ECMAScript 6(ES6)引入了 Set、Map、WeakSet 和 WeakMap 数据结构,它们提供了更灵活和高效的方式来存储和管理数据。
Set
是一种集合类型,允许存储唯一的值。它的主要特性是每个值只能出现一次。Map
是一种键值对集合,允许使用任何类型的值作为键。它的主要特性是键的顺序是有序的。WeakSet
是一种类似于 Set
的集合,但它只允许对象作为成员,并且对其成员的引用是弱引用。这意味着如果没有其他引用指向 WeakSet
中的对象,它们可以被垃圾回收。WeakMap
是一种类似于 Map
的集合,但它的键是弱引用。这意味着如果没有其他引用指向 WeakMap
中的键,它们可以被垃圾回收。提示
关于 JavaScript-Set、Map、WeakSet和WeakMap 的详细内容可以查看:JavaScript-Set、Map、WeakSet和WeakMap
在 ECMAScript 6(ES6)中,引入了 Symbol 数据类型,它是一种新的原始数据类型,用于创建唯一的标识符。Symbol 的主要用途是为对象的属性提供唯一性,避免属性名的冲突。
for...in
或 Object.keys()
)列出。创建使用
const symbol1 = Symbol();
const symbol2 = Symbol('description');
const symbol3 = Symbol('description');
console.log(symbol1 === symbol2); // false
console.log(symbol2 === symbol3); // false
const symbol = Symbol('description');
const obj = {};
obj[symbol] = 'value';
console.log(obj[symbol]); // 'value'
内置Symbol
Symbol.iterator
: 用于定义对象的默认迭代器,使对象可以使用 for...of 循环。const myIterable = {
*[Symbol.iterator]() {
yield 1;
yield 2;
yield 3;
}
};
for (const value of myIterable) {
console.log(value); // 1, 2, 3
}
Symbol.asyncIterator
: 用于创建一个异步迭代器对象,用于遍历异步可迭代对象。const asyncIterable = {
async *[Symbol.asyncIterator]() {
yield 1;
yield 2;
yield 3;
}
};
(async () => {
for await (const value of asyncIterable) {
console.log(value); // 1, 2, 3
}
})();
Symbol.toStringTag
: 用于定义一个对象的字符串描述。const myObject = {
[Symbol.toStringTag]: 'MyCustomObject'
};
console.log(Object.prototype.toString.call(myObject)); // '[object MyCustomObject]'
Symbol.hasInstance
: 用于自定义 instanceof 操作符的行为。class MyClass {
static [Symbol.hasInstance](instance) {
return instance.customProperty === true;
}
}
const obj = { customProperty: true };
console.log(obj instanceof MyClass); // true
Symbol.isConcatSpreadable
: 用于指示一个对象是否可以被 concat()
方法展开。const myArray = [1, 2];
const myObject = {
[Symbol.isConcatSpreadable]: true,
0: 3,
1: 4,
length: 2
};
const newArray = myArray.concat(myObject); // [1, 2, 3, 4]
Symbol.unscopables
:用于定义哪些属性不应被 with 语句访问。const myObject = {
a: 1,
b: 2,
[Symbol.unscopables]: { b: true }
};
with (myObject) {
console.log(a); // 1
console.log(b); // ReferenceError: b is not defined
}
ECMAScript 2015,引入了许多新的方法和功能,极大地增强了 JavaScript 的能力。
Array.from()
: 将类数组对象或可迭代对象转换为数组。const arrayLike = { 0: 'a', 1: 'b', length: 2 };
const arr = Array.from(arrayLike); // ['a', 'b']
Array.of()
: 创建一个新的数组实例,使用一组指定的元素。const arr = Array.of(1, 2, 3); // [1, 2, 3]
Array.prototype.fill()
: 用静态值填充数组的所有元素。const arr = new Array(3).fill(0); // [0, 0, 0]
Array.prototype.find()
: 返回数组中满足提供的测试函数的第一个元素的值。const numbers = [1, 2, 3, 4, 5];
const found = numbers.find(num => num > 3); // 4
Array.prototype.findIndex()
: 返回数组中满足提供的测试函数的第一个元素的索引。const index = numbers.findIndex(num => num > 3); // 3
Array.prototype.copyWithin()
: 在数组内部复制指定位置的元素到另一个位置。const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3);
console.log(arr); // 输出: [4, 5, 3, 4, 5]
String.prototype.includes()
: 判断一个字符串是否包含另一个字符串。const includes = str.includes('world'); // true
String.prototype.startsWith()
: 判断一个字符串是否以另一个字符串开头。const str = 'Hello, world!';
const starts = str.startsWith('Hello'); // true
String.prototype.endsWith()
: 判断一个字符串是否以另一个字符串结尾。const ends = str.endsWith('world!'); // true
String.prototype.repeat()
: 返回一个新字符串,表示将原字符串重复指定次数。const repeated = 'abc'.repeat(3); // 'abcabcabc'
Object.assign()
: 将所有可枚举的属性从一个或多个源对象复制到目标对象。const target = { a: 1 };
const source = { b: 2 };
const returnedTarget = Object.assign(target, source); // { a: 1, b: 2 }
Object.is()
: 判断两个值是否严格相等,类似于 ===,但处理 NaN 和 -0 的方式不同。Object.is(NaN, NaN); // true
Object.is(0, -0); // false
Object.keys()
: 返回一个数组,包含对象自身可枚举属性的名称。const obj = { a: 1, b: 2 };
console.log(Object.keys(obj)); // 输出: ['a', 'b']
Object.values()
: 返回一个由对象的自身可枚举属性值组成的数组。const values = Object.values(obj); // [1, 2]
Object.freeze()
: 冻结一个对象,使其不能被修改。const obj = { a: 1 };
Object.freeze(obj);
obj.a = 2; // 无效,obj.a 仍然是 1
Object.seal()
: 密封一个对象,防止添加新属性,但可以修改现有属性。const obj = { a: 1 };
Object.seal(obj);
obj.a = 2; // 有效
obj.b = 3; // 无效
Object.getOwnPropertyNames()
: 返回一个数组,包含对象自身的所有属性(包括非枚举属性)。const obj = Object.create({ b: 2 }, { a: { value: 1 } });
const propertyNames = Object.getOwnPropertyNames(obj); // ['a']
Number.isFinite()
: 判断一个值是否是有限的数字。Number.isFinite(2); // true
Number.isFinite(Infinity); // false
Number.isNaN()
: 判断一个值是否是 NaN。Number.isNaN(NaN); // true
Number.isNaN('NaN'); // false
Number.isInteger()
: 判断一个值是否是整数。Number.isInteger(4); // true
Number.isInteger(4.5); // false
Number.isSafeInteger()
: 判断一个值是否是安全整数。Number.isSafeInteger(10); // true
Number.isSafeInteger(Math.pow(2, 53)); // false