ES相关2.0
ES6 prox的作用
ES6 引入了 Proxy(代理),它是一种元编程特性,允许你拦截并自定义对象的基本操作(如属性查找、赋值、枚举等)。Proxy 的作用是为对象创建一个代理层,通过这个代理层可以控制对目标对象的访问和操作。
以下是 Proxy 的主要作用和应用场景:
- 基本用法
Proxy 的基本语法是:
const proxy = new Proxy(target, handler);target:目标对象,即需要被代理的对象。handler:一个对象,定义了拦截操作的“陷阱”(trap)函数。
示例:
const target = {
name: 'Alice',
age: 25
};
const handler = {
get(target, prop) {
if (prop === 'age') {
return target[prop] + ' years old';
}
return target[prop];
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Alice
console.log(proxy.age); // 25 years old- 常用的陷阱函数
handler 对象中可以定义多种陷阱函数来拦截不同的操作:
| 陷阱函数 | 拦截的操作 |
|---|---|
get(target, prop) | 读取属性时调用 |
set(target, prop, value) | 设置属性时调用 |
has(target, prop) | 使用in 操作符时调用 |
deleteProperty(target, prop) | 使用delete 操作符时调用 |
apply(target, thisArg, args) | 调用函数时调用(用于代理函数) |
construct(target, args) | 使用new 操作符时调用(用于代理构造函数) |
ownKeys(target) | 获取对象自身属性键时调用 |
示例:拦截属性读取和设置
const target = {
name: 'Alice',
age: 25
};
const handler = {
get(target, prop) {
console.log(`Reading property: ${prop}`);
return target[prop];
},
set(target, prop, value) {
console.log(`Setting property: ${prop} = ${value}`);
target[prop] = value;
return true; // 表示设置成功
}
};
const proxy = new Proxy(target, handler);
proxy.name; // 输出: Reading property: name
proxy.age = 30; // 输出: Setting property: age = 30- 验证和过滤
Proxy 可以用于验证或过滤对目标对象的操作,例如:
- 验证属性值是否符合要求。
- 防止某些属性被修改或删除。
示例:验证属性值
const target = {
age: 25
};
const handler = {
set(target, prop, value) {
if (prop === 'age' && typeof value !== 'number') {
throw new TypeError('Age must be a number');
}
target[prop] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
proxy.age = 30; // 正常
proxy.age = '30'; // 抛出错误: Age must be a number- 函数代理
Proxy 不仅可以代理对象,还可以代理函数。通过 apply 陷阱函数,可以拦截函数的调用。
示例:拦截函数调用
function sum(a, b) {
return a + b;
}
const handler = {
apply(target, thisArg, args) {
console.log(`Calling function with arguments: ${args}`);
return target(...args);
}
};
const proxy = new Proxy(sum, handler);
console.log(proxy(1, 2)); // 输出: Calling function with arguments: 1,2
// 输出: 3- 构造函数代理
通过 construct 陷阱函数,可以拦截 new 操作符对构造函数的调用。
示例:拦截构造函数调用
class Person {
constructor(name) {
this.name = name;
}
}
const handler = {
construct(target, args) {
console.log(`Creating instance with arguments: ${args}`);
return new target(...args);
}
};
const ProxyPerson = new Proxy(Person, handler);
const alice = new ProxyPerson('Alice'); // 输出: Creating instance with arguments: Alice
console.log(alice.name); // Alice- 隐藏私有属性
Proxy 可以用于隐藏对象的私有属性,使其无法被直接访问。
示例:隐藏私有属性
const target = {
name: 'Alice',
_password: '123456'
};
const handler = {
get(target, prop) {
if (prop.startsWith('_')) {
throw new Error('Access denied');
}
return target[prop];
},
set(target, prop, value) {
if (prop.startsWith('_')) {
throw new Error('Access denied');
}
target[prop] = value;
return true;
}
};
const proxy = new Proxy(target, handler);
console.log(proxy.name); // Alice
console.log(proxy._password); // 抛出错误: Access denied- 应用场景
- 数据验证:拦截属性赋值操作,验证数据是否符合要求。
- 日志记录:记录对象的读写操作。
- 缓存:拦截函数调用,实现缓存机制。
- 隐藏私有属性:防止私有属性被直接访问。
- 观察者模式:监听对象的变化并触发回调。
示例:观察者模式
const target = {
name: 'Alice'
};
const observers = [];
const handler = {
set(target, prop, value) {
target[prop] = value;
observers.forEach(observer => observer(prop, value));
return true;
}
};
const proxy = new Proxy(target, handler);
observers.push((prop, value) => {
console.log(`Property ${prop} changed to ${value}`);
});
proxy.name = 'Bob'; // 输出: Property name changed to Bob- 与
Reflect结合使用
Reflect 是 ES6 引入的一个内置对象,提供了与 Proxy 陷阱函数一一对应的方法。通常可以将 Proxy 和 Reflect 结合使用,以简化代码。
示例:
const target = {
name: 'Alice'
};
const handler = {
get(target, prop) {
console.log(`Reading property: ${prop}`);
return Reflect.get(target, prop);
},
set(target, prop, value) {
console.log(`Setting property: ${prop} = ${value}`);
return Reflect.set(target, prop, value);
}
};
const proxy = new Proxy(target, handler);
proxy.name; // 输出: Reading property: name
proxy.name = 'Bob'; // 输出: Setting property: name = Bob总结
Proxy 是 ES6 引入的一种强大的元编程工具,允许你拦截并自定义对象的基本操作。它的主要作用包括数据验证、日志记录、缓存、隐藏私有属性等。通过 Proxy,你可以更灵活地控制对象的行为,实现更高级的功能。
ES6 map的作用
ES6 引入了 Map 数据结构,它是一种键值对的集合,与传统的对象(Object)相比,Map 的键可以是任意类型的值(包括对象),而不仅仅是字符串或 Symbol。Map 提供了更强大的功能和更直观的 API,适用于需要复杂键值对的场景。
以下是 Map 的主要作用和应用场景:
- 键的类型更灵活
Map 的键可以是任意类型的值,包括对象、函数、基本类型等,而 Object 的键只能是字符串或 Symbol。
示例:
const map = new Map();
const key1 = { name: 'Alice' };
const key2 = function() {};
const key3 = 'key3';
map.set(key1, 'value1');
map.set(key2, 'value2');
map.set(key3, 'value3');
console.log(map.get(key1)); // value1
console.log(map.get(key2)); // value2
console.log(map.get(key3)); // value3- 保持插入顺序
Map 会严格保持键值对的插入顺序,而 Object 的键顺序是不确定的。
示例:
const map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
for (let [key, value] of map) {
console.log(key, value); // a 1, b 2, c 3
}- 常用操作
Map 提供了一些常用的方法来操作键值对:
set(key, value):添加或更新键值对。get(key):获取指定键对应的值。has(key):检查Map中是否包含某个键。delete(key):删除指定键的键值对。clear():清空Map中的所有键值对。size:获取Map中键值对的数量。
示例:
const map = new Map();
map.set('name', 'Alice');
map.set('age', 25);
console.log(map.size); // 2
console.log(map.get('name')); // Alice
console.log(map.has('age')); // true
map.delete('age');
console.log(map.size); // 1
map.clear();
console.log(map.size); // 0- 遍历 Map
Map 是可迭代的,可以使用 for...of 循环或 forEach 方法遍历其中的键值对。
示例:
const map = new Map();
map.set('a', 1);
map.set('b', 2);
map.set('c', 3);
// 使用 for...of 遍历
for (let [key, value] of map) {
console.log(key, value); // a 1, b 2, c 3
}
// 使用 forEach 遍历
map.forEach((value, key) => {
console.log(key, value); // a 1, b 2, c 3
});- 与对象的区别
| 特性 | Map | Object |
|---|---|---|
| 键的类型 | 任意类型(包括对象) | 字符串或 Symbol |
| 键的顺序 | 严格保持插入顺序 | 不确定 |
| 大小 | 通过size 属性获取 | 需要手动计算 |
| 性能 | 频繁增删键值对时性能更好 | 频繁增删键值对时性能较差 |
| 默认键 | 无默认键 | 有原型链上的默认键 |
- 应用场景
- 复杂键值对:当键需要是对象或其他复杂类型时,使用
Map。 - 保持顺序:当需要严格保持键值对的插入顺序时,使用
Map。 - 频繁增删:当需要频繁添加或删除键值对时,
Map的性能更好。 - 数据缓存:可以用
Map实现简单的缓存机制。
示例:数据缓存
const cache = new Map();
function getData(key) {
if (cache.has(key)) {
return cache.get(key);
}
const data = fetchDataFromServer(key); // 假设从服务器获取数据
cache.set(key, data);
return data;
}- WeakMap
ES6 还引入了 WeakMap,它与 Map 类似,但有以下区别:
WeakMap的键必须是对象,不能是基本类型。WeakMap中的键是弱引用的,不会阻止垃圾回收。WeakMap不可遍历。
示例:
const weakMap = new WeakMap();
const obj = { name: 'Alice' };
weakMap.set(obj, 'value1');
console.log(weakMap.get(obj)); // value1
// 当 obj 被垃圾回收后,weakMap 中的键值对也会自动消失- 与数组的转换
Map 可以轻松地与数组相互转换。
示例:
// 数组转 Map
const array = [['a', 1], ['b', 2], ['c', 3]];
const map = new Map(array);
console.log(map.get('a')); // 1
// Map 转数组
const newArray = [...map];
console.log(newArray); // [['a', 1], ['b', 2], ['c', 3]]总结
Map 是 ES6 引入的一种强大的键值对集合,支持任意类型的键,并保持插入顺序。它比传统的 Object 更适合处理复杂键值对和频繁增删的场景。如果需要存储对象键并且不希望阻止垃圾回收,可以使用 WeakMap。
ES6 set的作用
ES6 引入了 Set 数据结构,它是一种无序且唯一的值的集合。Set 的主要作用是存储不重复的值,并提供高效的方法来检查某个值是否存在。
以下是 Set 的主要作用和应用场景:
- 存储唯一值
Set 的核心特性是它的值总是唯一的,重复的值会被自动忽略。这使得 Set 非常适合用于去重。
示例:
const numbers = [1, 2, 3, 4, 2, 3, 5];
const uniqueNumbers = new Set(numbers);
console.log(uniqueNumbers); // Set { 1, 2, 3, 4, 5 }- 高效的值检查
Set 内部使用哈希表实现,因此检查某个值是否存在于 Set 中的时间复杂度是 O(1),比数组的 includes() 方法(时间复杂度为 O(n))更高效。
示例:
const fruits = new Set(['apple', 'banana', 'orange']);
console.log(fruits.has('banana')); // true
console.log(fruits.has('grape')); // false- 常用操作
Set 提供了一些常用的方法来操作集合:
add(value):向Set中添加一个值。delete(value):从Set中删除一个值。has(value):检查Set中是否包含某个值。clear():清空Set中的所有值。size:获取Set中值的数量。
示例:
const colors = new Set();
colors.add('red');
colors.add('green');
colors.add('blue');
colors.add('red'); // 重复值会被忽略
console.log(colors.size); // 3
console.log(colors.has('green')); // true
colors.delete('blue');
console.log(colors); // Set { 'red', 'green' }
colors.clear();
console.log(colors.size); // 0- 遍历 Set
Set 是可迭代的,可以使用 for...of 循环或 forEach 方法遍历其中的值。
示例:
const letters = new Set(['a', 'b', 'c']);
// 使用 for...of 遍历
for (let letter of letters) {
console.log(letter); // a, b, c
}
// 使用 forEach 遍历
letters.forEach((value) => {
console.log(value); // a, b, c
});- 与数组的转换
Set 可以轻松地与数组相互转换,常用于数组去重。
示例:
// 数组去重
const array = [1, 2, 3, 3, 4, 5, 5];
const uniqueArray = [...new Set(array)]; // 将 Set 转换为数组
console.log(uniqueArray); // [1, 2, 3, 4, 5]- 存储非原始类型的值
Set 可以存储任何类型的值,包括对象、函数等。需要注意的是,Set 是通过严格相等(===)来判断值是否重复的,因此两个看起来相同的对象会被认为是不同的值。
示例:
const obj1 = { name: 'Alice' };
const obj2 = { name: 'Alice' };
const set = new Set();
set.add(obj1);
set.add(obj2);
console.log(set.size); // 2,因为 obj1 和 obj2 是不同的对象- 应用场景
- 数组去重:快速去除数组中的重复值。
- 值的存在性检查:高效地检查某个值是否存在于集合中。
- 数学集合运算:如并集、交集、差集等。
- 存储唯一数据:如用户 ID、订单号等需要唯一性的数据。
示例:集合运算
// 并集
const set1 = new Set([1, 2, 3]);
const set2 = new Set([3, 4, 5]);
const union = new Set([...set1, ...set2]);
console.log([...union]); // [1, 2, 3, 4, 5]
// 交集
const intersection = new Set([...set1].filter(x => set2.has(x)));
console.log([...intersection]); // [3]
// 差集
const difference = new Set([...set1].filter(x => !set2.has(x)));
console.log([...difference]); // [1, 2]- WeakSet
ES6 还引入了 WeakSet,它与 Set 类似,但有以下区别:
WeakSet只能存储对象,不能存储原始值。WeakSet中的对象是弱引用的,不会阻止垃圾回收。WeakSet不可遍历。
示例:
const weakSet = new WeakSet();
const obj = { name: 'Alice' };
weakSet.add(obj);
console.log(weakSet.has(obj)); // true
// 当 obj 被垃圾回收后,weakSet 中的引用也会自动消失总结
Set 是 ES6 引入的一种高效的数据结构,用于存储唯一的值。它的主要作用包括去重、高效的值检查、集合运算等。与数组相比,Set 在处理唯一性和存在性检查时更加高效。如果需要存储对象并且不希望阻止垃圾回收,可以使用 WeakSet。
ES6 symbol的作用
ES6 引入了 Symbol 类型,它是一种新的原始数据类型,用于创建唯一的、不可变的值。Symbol 的主要作用是作为对象属性的唯一标识符,避免属性名冲突,同时也可以用于定义一些特殊的行为(如自定义迭代器)。
以下是 Symbol 的主要作用和应用场景:
- 创建唯一的属性键
Symbol 的主要用途是作为对象属性的键,确保属性名不会与其他属性名冲突。因为每个 Symbol 值都是唯一的,即使它们的描述相同。
示例:
const id = Symbol('id'); // 创建一个 Symbol,描述为 'id'
const user = {
name: 'Alice',
[id]: 123 // 使用 Symbol 作为属性键
};
console.log(user[id]); // 123
console.log(Object.keys(user)); // ['name'],Symbol 属性不会被枚举- 避免属性名冲突
在大型项目中,可能会在不同的模块中使用相同的字符串作为属性名,这可能导致属性名冲突。使用 Symbol 可以避免这种问题,因为每个 Symbol 都是唯一的。
示例:
const module1 = {
id: 1
};
const module2 = {
id: 2
};
// 使用 Symbol 避免冲突
const id = Symbol('id');
module1[id] = 1;
module2[id] = 2;
console.log(module1[id]); // 1
console.log(module2[id]); // 2- 定义对象的私有属性
Symbol 可以用作对象的私有属性,因为 Symbol 属性不会被常规方法(如 for...in、Object.keys()、Object.getOwnPropertyNames())枚举到。
示例:
const age = Symbol('age');
const person = {
name: 'Alice',
[age]: 25
};
console.log(person[age]); // 25
for (let key in person) {
console.log(key); // 只输出 'name'
}- 内置 Symbol 值
ES6 提供了一些内置的 Symbol 值,用于定义对象的特殊行为。这些内置 Symbol 值被称为“Well-Known Symbols”,例如:
Symbol.iterator:定义对象的默认迭代器。Symbol.toStringTag:定义对象的toString行为。Symbol.hasInstance:定义instanceof的行为。
示例:
// 自定义对象的迭代行为
const myIterable = {
[Symbol.iterator]: function* () {
yield 1;
yield 2;
yield 3;
}
};
for (let value of myIterable) {
console.log(value); // 1, 2, 3
}- 全局 Symbol 注册表
ES6 提供了 Symbol.for() 和 Symbol.keyFor() 方法,用于创建和访问全局 Symbol 注册表中的 Symbol 值。
Symbol.for(key):如果全局注册表中存在与key对应的Symbol,则返回它;否则创建一个新的Symbol并注册。Symbol.keyFor(sym):返回全局注册表中与sym对应的key。
示例:
const sym1 = Symbol.for('mySymbol'); // 创建或获取全局 Symbol
const sym2 = Symbol.for('mySymbol');
console.log(sym1 === sym2); // true
console.log(Symbol.keyFor(sym1)); // 'mySymbol'- Symbol 的特性
- 唯一性:每个
Symbol值都是唯一的,即使它们的描述相同。 - 不可变性:
Symbol值是不可变的,不能被修改。 - 不可枚举性:
Symbol属性不会被for...in、Object.keys()等枚举到。 - 类型检测:
typeof Symbol()返回'symbol'。
示例:
const sym1 = Symbol('foo');
const sym2 = Symbol('foo');
console.log(sym1 === sym2); // false,Symbol 是唯一的
console.log(typeof sym1); // 'symbol'- Symbol 的应用场景
- 避免属性名冲突:在大型项目或库中,使用
Symbol作为属性键可以避免命名冲突。 - 定义私有属性:
Symbol属性不会被常规方法枚举,适合用于定义私有属性。 - 自定义对象行为:通过内置
Symbol值(如Symbol.iterator)可以定义对象的特殊行为。 - 元编程:
Symbol可以用于定义对象的元数据或特殊行为。
总结
Symbol 是 ES6 引入的一种新的原始数据类型,主要用于创建唯一的属性键,避免属性名冲突,同时也可以用于定义对象的特殊行为(如迭代器)。它的唯一性和不可枚举性使其非常适合用于定义私有属性或元数据。
ES6对function函数类型做的常用升级优化
ES6(ECMAScript 2015)对JavaScript中的function函数类型进行了多项优化和升级,主要包括以下几个方面:
- 箭头函数(Arrow Functions)
箭头函数是ES6引入的一种新的函数语法,简化了函数的定义,并且自动绑定了this。
特点:
- 语法简洁:
(参数) => { 函数体 } - 自动绑定
this:箭头函数没有自己的this,它会捕获所在上下文的this值。 - 不能作为构造函数使用,不能使用
new调用。 - 没有
arguments对象,但可以使用剩余参数(...args)。
示例:
// ES5
var add = function(a, b) {
return a + b;
};
// ES6
const add = (a, b) => a + b;- 默认参数(Default Parameters)
ES6允许为函数的参数设置默认值,简化了参数处理的逻辑。
示例:
// ES5
function greet(name) {
name = name || 'Guest';
console.log('Hello, ' + name);
}
// ES6
function greet(name = 'Guest') {
console.log(`Hello, ${name}`);
}- 剩余参数(Rest Parameters)
剩余参数允许将不定数量的参数表示为一个数组,替代了ES5中的arguments对象。
示例:
// ES5
function sum() {
var args = Array.prototype.slice.call(arguments);
return args.reduce(function(a, b) {
return a + b;
}, 0);
}
// ES6
function sum(...args) {
return args.reduce((a, b) => a + b, 0);
}- 扩展运算符(Spread Operator)
扩展运算符可以将数组或对象展开为多个参数,常用于函数调用时。
示例:
const numbers = [1, 2, 3];
// ES5
Math.max.apply(null, numbers);
// ES6
Math.max(...numbers);- 函数参数的解构赋值(Destructuring Assignment)
ES6允许在函数参数中使用解构赋值,直接从对象或数组中提取值。
示例:
// 对象解构
function greet({ name, age }) {
console.log(`Hello, ${name}. You are ${age} years old.`);
}
const person = { name: 'Alice', age: 25 };
greet(person);
// 数组解构
function sum([a, b, c]) {
return a + b + c;
}
const nums = [1, 2, 3];
console.log(sum(nums)); // 6- 函数名称属性(Function Name Property)
ES6为函数添加了name属性,可以获取函数的名称。
示例:
function foo() {}
console.log(foo.name); // "foo"
const bar = function() {};
console.log(bar.name); // "bar"
const baz = () => {};
console.log(baz.name); // "baz"- 尾调用优化(Tail Call Optimization)
ES6引入了尾调用优化,允许在函数的最后一步调用另一个函数时,不增加新的栈帧,从而避免栈溢出。
示例:
function factorial(n, acc = 1) {
if (n <= 1) return acc;
return factorial(n - 1, n * acc); // 尾调用优化
}
console.log(factorial(5)); // 120- 块级作用域函数声明(Block-Scoped Function Declarations)
在ES6中,函数声明在块级作用域内是块级作用域的,而不是像ES5中那样提升到函数或全局作用域的顶部。
示例:
{
function foo() {
console.log('Inside block');
}
foo(); // "Inside block"
}
foo(); // ReferenceError: foo is not defined总结
ES6对函数类型的优化使得代码更加简洁、易读,并且提供了更多的功能,如箭头函数、默认参数、剩余参数、解构赋值等。这些改进不仅提升了开发效率,还增强了代码的可维护性和可读性。
ECMAScript 7、8、9新特性
ECMAScript 每年都会发布新版本,ES7(2016)、ES8(2017)和 ES9(2018)分别引入了一些新特性。以下是这些版本的主要更新内容:
ECMAScript 2016(ES7)
ES7 是一个较小的更新,只引入了两个新特性。
Array.prototype.includes()
判断数组是否包含某个值,返回布尔值。
示例:
const arr = [1, 2, 3];
console.log(arr.includes(2)); // 输出: true
console.log(arr.includes(4)); // 输出: false- 指数运算符 (
**)
用于计算幂运算。
示例:
console.log(2 ** 3); // 输出: 8
console.log(3 ** 2); // 输出: 9ECMAScript 2017(ES8)
ES8 引入了更多实用的特性,主要集中在异步编程和对象操作上。
async/await
简化异步操作,使异步代码看起来像同步代码。
示例:
async function fetchData() {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
return data;
}Object.values()
返回对象所有可枚举属性值的数组。
示例:
const obj = { a: 1, b: 2, c: 3 };
console.log(Object.values(obj)); // 输出: [1, 2, 3]Object.entries()
返回对象所有可枚举属性的键值对数组。
示例:
const obj = { a: 1, b: 2, c: 3 };
console.log(Object.entries(obj)); // 输出: [['a', 1], ['b', 2], ['c', 3]]Object.getOwnPropertyDescriptors()
返回对象所有自身属性的描述符(包括 value、writable、enumerable 和 configurable)。
示例:
const obj = { a: 1 };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
// 输出:
// {
// a: { value: 1, writable: true, enumerable: true, configurable: true }
// }- 字符串填充方法:
padStart()和padEnd()
在字符串的开头或结尾填充指定字符,直到字符串达到指定长度。
示例:
console.log('5'.padStart(3, '0')); // 输出: "005"
console.log('5'.padEnd(3, '*')); // 输出: "5**"- 函数参数列表和调用中的尾逗号
允许在函数参数列表和调用时使用尾逗号。
示例:
function foo(a, b, c,) {
console.log(a, b, c);
}
foo(1, 2, 3,);ECMAScript 2018(ES9)
ES9 进一步增强了异步编程和对象操作的能力。
- 异步迭代器 (
for-await-of)
用于遍历异步可迭代对象(如异步生成器)。
示例:
async function* asyncGenerator() {
yield 1;
yield 2;
yield 3;
}
(async () => {
for await (const value of asyncGenerator()) {
console.log(value);
}
})();
// 输出: 1, 2, 3Promise.prototype.finally()
无论 Promise 是成功还是失败,都会执行的回调函数。
示例:
fetch('https://api.example.com/data')
.then(response => response.json())
.catch(error => console.error(error))
.finally(() => console.log('请求完成'));- Rest/Spread 属性
允许在对象中使用 ... 进行剩余参数和展开操作。
示例:
// Rest 属性
const { a, ...rest } = { a: 1, b: 2, c: 3 };
console.log(rest); // 输出: { b: 2, c: 3 }
// Spread 属性
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 };
console.log(obj2); // 输出: { a: 1, b: 2, c: 3 }- 正则表达式的增强
- 命名捕获组:使用
(?<name>...)语法为捕获组命名。 - 反向断言:支持
(?<=...)和(?<!...)语法。 s标志:使.匹配任意字符,包括换行符。
示例:
// 命名捕获组
const regex = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = regex.exec('2023-10-05');
console.log(match.groups.year); // 输出: 2023
console.log(match.groups.month); // 输出: 10
// s 标志
const regex2 = /a.b/s;
console.log(regex2.test('a\nb')); // 输出: true总结
- ES7(2016):
Array.prototype.includes()和指数运算符 (**)。 - ES8(2017):
async/await、Object.values()、Object.entries()、padStart()、padEnd()等。 - ES9(2018):异步迭代器、
Promise.prototype.finally()、Rest/Spread 属性、正则表达式增强等。
这些新特性使得 JavaScript 更加现代化和强大,尤其是在异步编程和对象操作方面。
ES6对象方法扩展
ES6(ECMAScript 2015)为对象(Object)引入了许多新的方法和语法糖,使得对象的操作更加简洁和强大。以下是 ES6 中对象方法的主要扩展:
- 属性简写
在对象字面量中,如果属性名和变量名相同,可以省略属性值。
示例:
const name = 'Alice';
const age = 25;
// ES5
const obj1 = {
name: name,
age: age
};
// ES6
const obj2 = { name, age };
console.log(obj2); // 输出: { name: 'Alice', age: 25 }- 方法简写
在对象字面量中,定义方法时可以省略 function 关键字。
示例:
// ES5
const obj1 = {
sayHello: function() {
console.log('Hello');
}
};
// ES6
const obj2 = {
sayHello() {
console.log('Hello');
}
};
obj2.sayHello(); // 输出: Hello- 计算属性名
在对象字面量中,可以使用表达式作为属性名,用 [] 包裹。
示例:
const prop = 'name';
const obj = {
[prop]: 'Alice',
['age']: 25
};
console.log(obj); // 输出: { name: 'Alice', age: 25 }Object.is()
用于比较两个值是否严格相等,与 === 类似,但处理了一些特殊情况(如 NaN 和 +0/-0)。
示例:
console.log(Object.is(NaN, NaN)); // 输出: true
console.log(Object.is(+0, -0)); // 输出: false
console.log(Object.is(42, 42)); // 输出: trueObject.assign()
用于将一个或多个源对象的属性复制到目标对象,返回目标对象。
示例:
const target = { a: 1 };
const source1 = { b: 2 };
const source2 = { c: 3 };
const result = Object.assign(target, source1, source2);
console.log(result); // 输出: { a: 1, b: 2, c: 3 }Object.setPrototypeOf()
设置一个对象的原型(即 __proto__ 属性)。
示例:
const obj = {};
const proto = { foo: 'bar' };
Object.setPrototypeOf(obj, proto);
console.log(obj.foo); // 输出: barObject.getPrototypeOf()
获取一个对象的原型。
示例:
const obj = {};
const proto = { foo: 'bar' };
Object.setPrototypeOf(obj, proto);
console.log(Object.getPrototypeOf(obj) === proto); // 输出: trueObject.keys()、Object.values()和Object.entries()
Object.keys():返回对象自身可枚举属性的键名数组。Object.values():返回对象自身可枚举属性的值数组。Object.entries():返回对象自身可枚举属性的键值对数组。
示例:
const obj = { a: 1, b: 2, c: 3 };
console.log(Object.keys(obj)); // 输出: ['a', 'b', 'c']
console.log(Object.values(obj)); // 输出: [1, 2, 3]
console.log(Object.entries(obj)); // 输出: [['a', 1], ['b', 2], ['c', 3]]Object.fromEntries()
将键值对数组转换为对象(与 Object.entries() 相反)。
示例:
const entries = [['a', 1], ['b', 2], ['c', 3]];
const obj = Object.fromEntries(entries);
console.log(obj); // 输出: { a: 1, b: 2, c: 3 }super关键字
在对象方法中,super 用于调用父对象的方法。
示例:
const parent = {
sayHello() {
console.log('Hello from parent');
}
};
const child = {
sayHello() {
super.sayHello();
console.log('Hello from child');
}
};
Object.setPrototypeOf(child, parent);
child.sayHello();
// 输出:
// Hello from parent
// Hello from childObject.getOwnPropertyDescriptors()
返回对象所有自身属性的描述符(包括 value、writable、enumerable 和 configurable)。
示例:
const obj = { a: 1 };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
// 输出:
// {
// a: { value: 1, writable: true, enumerable: true, configurable: true }
// }Symbol作为属性名
ES6 引入了 Symbol 类型,可以用作对象的唯一属性名。
示例:
const key = Symbol('key');
const obj = {
[key]: 'value'
};
console.log(obj[key]); // 输出: value总结
ES6 为对象引入了许多实用的扩展和方法,包括:
- 属性简写和方法简写。
- 计算属性名。
- 新的
Object方法:is()、assign()、setPrototypeOf()、getPrototypeOf()等。 Object.keys()、Object.values()和Object.entries()。super关键字。Symbol作为属性名。
这些扩展使得对象的操作更加简洁和强大,是现代 JavaScript 开发中不可或缺的工具。
ES6的数值扩展
ES6(ECMAScript 2015)为数值(Number)类型引入了许多新的扩展和方法,使得数值操作更加方便和强大。以下是 ES6 中数值的主要扩展:
- 二进制和八进制表示法
ES6 引入了新的字面量表示法,用于直接表示二进制和八进制数值。
- 二进制:前缀
0b或0B。 - 八进制:前缀
0o或0O。
示例:
const binary = 0b1010; // 二进制,表示十进制的 10
const octal = 0o12; // 八进制,表示十进制的 10
console.log(binary); // 输出: 10
console.log(octal); // 输出: 10Number.isFinite()
判断一个值是否为有限的数值(即不是 Infinity、-Infinity 或 NaN)。
示例:
console.log(Number.isFinite(42)); // 输出: true
console.log(Number.isFinite(Infinity)); // 输出: false
console.log(Number.isFinite(NaN)); // 输出: falseNumber.isNaN()
判断一个值是否为 NaN。与全局的 isNaN() 不同,Number.isNaN() 不会进行类型转换。
示例:
console.log(Number.isNaN(NaN)); // 输出: true
console.log(Number.isNaN('NaN')); // 输出: false
console.log(isNaN('NaN')); // 输出: true(全局 isNaN 会进行类型转换)Number.parseInt()和Number.parseFloat()
将全局方法 parseInt() 和 parseFloat() 移植到 Number 对象上,行为与全局方法一致。
示例:
console.log(Number.parseInt('42px')); // 输出: 42
console.log(Number.parseFloat('3.14abc')); // 输出: 3.14Number.isInteger()
判断一个值是否为整数。
示例:
console.log(Number.isInteger(42)); // 输出: true
console.log(Number.isInteger(42.0)); // 输出: true
console.log(Number.isInteger(42.1)); // 输出: falseNumber.EPSILON
表示 JavaScript 中数值的最小精度,用于浮点数比较。
示例:
console.log(Number.EPSILON); // 输出: 2.220446049250313e-16
function isEqual(a, b) {
return Math.abs(a - b) < Number.EPSILON;
}
console.log(isEqual(0.1 + 0.2, 0.3)); // 输出: trueNumber.isSafeInteger()
判断一个值是否为安全整数(即在 Number.MIN_SAFE_INTEGER 和 Number.MAX_SAFE_INTEGER 之间)。
示例:
console.log(Number.isSafeInteger(42)); // 输出: true
console.log(Number.isSafeInteger(Math.pow(2, 53))); // 输出: falseNumber.MAX_SAFE_INTEGER和Number.MIN_SAFE_INTEGER
表示 JavaScript 中安全整数的最大值和最小值。
示例:
console.log(Number.MAX_SAFE_INTEGER); // 输出: 9007199254740991
console.log(Number.MIN_SAFE_INTEGER); // 输出: -9007199254740991Math对象的扩展
ES6 为 Math 对象新增了一些方法,用于数值计算:
(1) Math.trunc()
去除小数部分,返回整数部分。
示例:
console.log(Math.trunc(3.14)); // 输出: 3
console.log(Math.trunc(-3.14)); // 输出: -3(2) Math.sign()
判断一个数的符号,返回 1(正数)、-1(负数)、0(零)、-0(负零)或 NaN(非数值)。
示例:
console.log(Math.sign(42)); // 输出: 1
console.log(Math.sign(-42)); // 输出: -1
console.log(Math.sign(0)); // 输出: 0
console.log(Math.sign(-0)); // 输出: -0
console.log(Math.sign('foo')); // 输出: NaN(3) Math.cbrt()
计算一个数的立方根。
示例:
console.log(Math.cbrt(27)); // 输出: 3(4) Math.hypot()
计算所有参数的平方和的平方根(即欧几里得距离)。
示例:
console.log(Math.hypot(3, 4)); // 输出: 5(5) Math.log2() 和 Math.log10()
分别计算以 2 和 10 为底的对数。
示例:
console.log(Math.log2(8)); // 输出: 3
console.log(Math.log10(100)); // 输出: 2- 指数运算符 (
**)
ES6 引入了指数运算符 (**),用于计算幂运算。
示例:
console.log(2 ** 3); // 输出: 8
console.log(3 ** 2); // 输出: 9总结
ES6 为数值类型引入了许多实用的扩展和方法,包括:
- 二进制和八进制表示法。
- 新的
Number方法:isFinite()、isNaN()、isInteger()、isSafeInteger()等。 - 新的
Math方法:trunc()、sign()、cbrt()、hypot()等。 - 指数运算符 (
**)。
这些扩展使得数值操作更加方便和精确,是现代 JavaScript 开发中不可或缺的工具。
ES6与ECMAScript2015的关系
ES6 和 ECMAScript 2015 是同一个东西,只是名称不同。以下是详细解释:
- ES6 是什么?
- ES6 是 ECMAScript 6 的简称,指的是 ECMAScript 的第 6 个版本。
- 它是 JavaScript 语言的一次重大更新,引入了许多新特性,使 JavaScript 更现代化、更强大。
- ECMAScript 2015 是什么?
- ECMAScript 2015 是 ECMAScript 第 6 个版本的正式名称。
- 从 ES6 开始,Ecma International 组织决定以发布年份命名 ECMAScript 版本,因此 ES6 也被称为 ECMAScript 2015(简称 ES2015)。
- 为什么有两个名字?
- 历史原因:
- 在 ES6 之前,ECMAScript 的版本号是以数字命名的(如 ES3、ES5)。
- 从 ES6 开始,Ecma International 决定改用年份命名(如 ES2015、ES2016),以便更清晰地反映版本的发布时间。
- 习惯问题:
- 由于 ES6 是一次重大更新,开发者习惯性地称其为 ES6,而不是 ES2015。
- 随着时间的推移,ES2015 的名称也逐渐被接受。
- ES6 和 ECMAScript 2015 的关系
- ES6 和 ECMAScript 2015 是同一个版本,只是命名方式不同。
- ES6 是传统的版本号命名。
- ECMAScript 2015 是基于发布年份的命名。
- ES6(ECMAScript 2015)的主要特性
ES6 是一次重大更新,引入了许多新特性,包括但不限于:
let和const:块级作用域变量声明。- 箭头函数:
() => {}。 - 模板字符串:
`Hello, ${name}`。 - 解构赋值:
const { a, b } = obj;。 - 默认参数:
function foo(a = 1) {}。 - 扩展运算符:
...。 - 类:
class关键字。 - 模块化:
import和export。 - Promise:用于异步编程。
- Symbol:新的原始数据类型。
- 迭代器和生成器:
for...of和function*。
- ES6 之后的版本命名
从 ES6 开始,ECMAScript 的版本改为按年份命名:
- ES2015(ES6):2015 年发布。
- ES2016(ES7):2016 年发布。
- ES2017(ES8):2017 年发布。
- ES2018(ES9):2018 年发布。
- ES2019(ES10):2019 年发布。
- ES2020(ES11):2020 年发布。
- ES2021(ES12):2021 年发布。
- ES2022(ES13):2022 年发布。
总结
- ES6 和 ECMAScript 2015 是同一个版本,只是命名方式不同。
- ES6 是 JavaScript 的一次重大更新,引入了许多现代语言特性。
- 从 ES6 开始,ECMAScript 的版本改为按年份命名(如 ES2015、ES2016 等)。
在实际开发中,ES6 和 ECMAScript 2015 可以互换使用,但更推荐使用 ES2015 以符合官方命名规范。
ECMAScript和JavaScript的关系
ECMAScript 和 JavaScript 是紧密相关的概念,但它们并不是完全相同的。以下是它们之间的关系和区别:
- JavaScript 是什么?
- JavaScript 是一种脚本语言,主要用于网页开发,使网页具有动态交互功能。
- 它最初由 Netscape 公司的 Brendan Eich 在 1995 年开发,最初命名为 Mocha,后来改为 LiveScript,最终命名为 JavaScript。
- JavaScript 不仅可以在浏览器中运行,还可以通过 Node.js 在服务器端运行。
- ECMAScript 是什么?
- ECMAScript 是 JavaScript 的标准化规范,由 Ecma International 组织制定。
- JavaScript 是 ECMAScript 规范的一种实现。
- ECMAScript 定义了语言的语法、类型、语句、关键字、操作符、对象等核心特性。
- ECMAScript 和 JavaScript 的关系
- ECMAScript 是标准,JavaScript 是实现:
- ECMAScript 是 JavaScript 的语言规范,规定了 JavaScript 应该如何实现。
- JavaScript 是 ECMAScript 规范的一种具体实现。
- 其他实现:
- 除了 JavaScript,还有其他语言也遵循 ECMAScript 规范,例如 ActionScript(用于 Adobe Flash)。
- 版本演进:
- ECMAScript 的版本号代表了 JavaScript 的核心特性更新。例如,ES5(2009 年发布)、ES6(2015 年发布,也称为 ES2015)、ES7(2016 年发布,也称为 ES2016)等。
- JavaScript 引擎(如 V8、SpiderMonkey)会根据 ECMAScript 规范实现这些特性。
- JavaScript 的组成部分
JavaScript 不仅仅包含 ECMAScript,还包括以下部分:
- ECMAScript:语言的核心(语法、类型、操作符等)。
- DOM(文档对象模型):用于操作 HTML 和 XML 文档的 API。
- BOM(浏览器对象模型):用于操作浏览器窗口的 API(如
window对象)。
- ECMAScript 的版本历史
ECMAScript 的版本更新推动了 JavaScript 的发展:
- ES3(1999):引入了正则表达式、
try/catch等特性。 - ES5(2009):引入了严格模式 (
"use strict")、JSON支持、数组方法(如map、filter)等。 - ES6(2015,也称为 ES2015):重大更新,引入了
let、const、箭头函数、类、模块、解构赋值等。 - ES2016(ES7):引入了
Array.prototype.includes()和指数运算符 (**)。 - ES2017(ES8):引入了
async/await、Object.values()、Object.entries()等。 - ES2018(ES9):引入了异步迭代、
Promise.prototype.finally()、Rest/Spread 属性等。 - ES2019(ES10):引入了
Array.prototype.flat()、Array.prototype.flatMap()、Object.fromEntries()等。 - ES2020(ES11):引入了可选链操作符 (
?.)、空值合并操作符 (??)、BigInt等。 - ES2021(ES12):引入了
String.prototype.replaceAll()、Promise.any()、逻辑赋值操作符 (&&=,||=,??=) 等。
总结
- ECMAScript 是 JavaScript 的标准化规范,定义了语言的核心特性。
- JavaScript 是 ECMAScript 的一种实现,同时还包括 DOM 和 BOM 等浏览器相关的 API。
- ECMAScript 的版本更新推动了 JavaScript 的发展,使其功能更加强大和现代化。
简单来说,ECMAScript 是规范,JavaScript 是实践。
ES7对象新增哪些扩展
ES7(ECMAScript 2016)相对于 ES6 来说是一个较小的更新,但它仍然为对象引入了一些实用的扩展。以下是 ES7 中对象的主要新增特性:
Object.values()
返回一个对象的所有可枚举属性值的数组。
语法:
Object.values(obj)示例:
const obj = { a: 1, b: 2, c: 3 };
const values = Object.values(obj);
console.log(values); // 输出: [1, 2, 3]Object.entries()
返回一个对象的所有可枚举属性键值对的数组,每个键值对是一个 [key, value] 数组。
语法:
Object.entries(obj)示例:
const obj = { a: 1, b: 2, c: 3 };
const entries = Object.entries(obj);
console.log(entries); // 输出: [['a', 1], ['b', 2], ['c', 3]]Object.getOwnPropertyDescriptors()
返回一个对象的所有自身属性的描述符(包括 value、writable、enumerable 和 configurable)。
语法:
Object.getOwnPropertyDescriptors(obj)示例:
const obj = { a: 1 };
const descriptors = Object.getOwnPropertyDescriptors(obj);
console.log(descriptors);
// 输出:
// {
// a: { value: 1, writable: true, enumerable: true, configurable: true }
// }- 指数运算符 (
**)
虽然不是直接针对对象的扩展,但 ES7 引入了指数运算符 (**),可以更方便地进行幂运算。
语法:
x ** y示例:
console.log(2 ** 3); // 输出: 8
console.log(3 ** 2); // 输出: 9Array.prototype.includes()
虽然不是对象的扩展,但 ES7 引入了 Array.prototype.includes() 方法,用于判断数组是否包含某个值。
语法:
array.includes(value)示例:
const arr = [1, 2, 3];
console.log(arr.includes(2)); // 输出: true
console.log(arr.includes(4)); // 输出: false总结
ES7 中对象的主要扩展包括:
Object.values():获取对象的所有值。Object.entries():获取对象的所有键值对。Object.getOwnPropertyDescriptors():获取对象属性的描述符。- 指数运算符 (
**):方便进行幂运算。 Array.prototype.includes():判断数组是否包含某个值。
这些扩展使得对象的操作更加方便和强大,尤其是在处理对象的键值对和属性描述符时非常有用。
ES6中数组新增了哪些扩展
ES6(ECMAScript 2015)为数组引入了许多新的扩展和方法,使得数组的操作更加方便和强大。以下是 ES6 中数组的主要扩展:
- 扩展运算符(Spread Operator)
扩展运算符 (...) 可以将数组展开为单独的元素,常用于函数调用、数组拼接等场景。
示例:
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2]; // 合并数组
console.log(combined); // 输出: [1, 2, 3, 4, 5, 6]
function sum(a, b, c) {
return a + b + c;
}
console.log(sum(...arr1)); // 输出: 6(展开数组作为参数)Array.from()
将类数组对象(如 arguments、NodeList)或可迭代对象(如 Set、Map)转换为真正的数组。
示例:
const nodeList = document.querySelectorAll('div');
const arr = Array.from(nodeList); // 将 NodeList 转换为数组
console.log(arr);Array.of()
创建一个包含任意数量参数的新数组,解决了 new Array() 的行为不一致问题。
示例:
const arr1 = Array.of(1, 2, 3); // 创建数组 [1, 2, 3]
const arr2 = new Array(3); // 创建长度为 3 的空数组
console.log(arr1); // 输出: [1, 2, 3]
console.log(arr2); // 输出: [empty × 3]- 数组实例的新方法
ES6 为数组实例添加了许多实用的方法:
(1) find()
查找数组中第一个满足条件的元素,返回该元素;如果没有找到,返回 undefined。
示例:
const arr = [1, 2, 3, 4];
const result = arr.find(item => item > 2);
console.log(result); // 输出: 3(2) findIndex()
查找数组中第一个满足条件的元素的索引,返回该索引;如果没有找到,返回 -1。
示例:
const arr = [1, 2, 3, 4];
const index = arr.findIndex(item => item > 2);
console.log(index); // 输出: 2(3) fill()
用指定的值填充数组。
示例:
const arr = [1, 2, 3];
arr.fill(0); // 填充为 [0, 0, 0]
console.log(arr);(4) includes()
判断数组是否包含某个值,返回布尔值。
示例:
const arr = [1, 2, 3];
console.log(arr.includes(2)); // 输出: true
console.log(arr.includes(4)); // 输出: false(5) flat()
将嵌套数组“拉平”,返回一个新数组。默认拉平一层,可以通过参数指定拉平的层数。
示例:
const arr = [1, [2, [3]]];
console.log(arr.flat()); // 输出: [1, 2, [3]]
console.log(arr.flat(2)); // 输出: [1, 2, 3](6) flatMap()
先对数组中的每个元素执行映射操作,然后将结果拉平一层。
示例:
const arr = [1, 2, 3];
const result = arr.flatMap(x => [x * 2]);
console.log(result); // 输出: [2, 4, 6]for...of循环
for...of 是遍历数组的新方式,直接获取数组的值(而不是索引)。
示例:
const arr = [1, 2, 3];
for (const value of arr) {
console.log(value); // 依次输出: 1, 2, 3
}entries()、keys()和values()
这些方法返回数组的迭代器对象,分别用于获取数组的键值对、键或值。
示例:
const arr = ['a', 'b', 'c'];
// entries() 返回键值对
for (const [index, value] of arr.entries()) {
console.log(index, value); // 输出: 0 'a', 1 'b', 2 'c'
}
// keys() 返回键
for (const key of arr.keys()) {
console.log(key); // 输出: 0, 1, 2
}
// values() 返回值
for (const value of arr.values()) {
console.log(value); // 输出: 'a', 'b', 'c'
}copyWithin()
将数组的一部分复制到同一数组的另一位置,并返回修改后的数组。
示例:
const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3); // 从索引 3 开始复制到索引 0
console.log(arr); // 输出: [4, 5, 3, 4, 5]Array.prototype[Symbol.iterator]
数组默认实现了迭代器协议,可以通过 Symbol.iterator 获取数组的迭代器。
示例:
const arr = [1, 2, 3];
const iterator = arr[Symbol.iterator]();
console.log(iterator.next()); // 输出: { value: 1, done: false }总结
ES6 为数组提供了许多强大的扩展和方法,包括:
- 扩展运算符 (
...) Array.from()和Array.of()- 新方法:
find()、findIndex()、fill()、includes()、flat()、flatMap()、copyWithin() - 新的遍历方式:
for...of、entries()、keys()、values()
这些扩展使得数组的操作更加简洁和高效,是现代 JavaScript 开发中不可或缺的工具。
ES中var、let、const区别
在 ECMAScript (ES) 中,var、let 和 const 都用于声明变量,但它们的行为和作用域有显著区别。以下是它们的详细对比:
var
- 作用域:函数作用域(function-scoped)。
- 在函数内部声明的变量只能在函数内部访问。
- 如果在函数外部声明,则成为全局变量。
- 变量提升:
var声明的变量会被提升到其作用域的顶部。- 变量可以在声明之前访问,但值为
undefined。
- 变量可以在声明之前访问,但值为
- 重复声明:允许在同一作用域内重复声明。
- 示例:javascript
function example() { if (true) { var x = 10; } console.log(x); // 输出: 10(因为 var 是函数作用域) } example();
let
- 作用域:块级作用域(block-scoped)。
- 在
{}块(如if、for、while等)中声明的变量只能在该块内访问。
- 在
- 变量提升:
let声明的变量也会被提升,但在声明之前访问会抛出ReferenceError(暂时性死区)。 - 重复声明:不允许在同一作用域内重复声明。
- 示例:javascript
function example() { if (true) { let y = 20; console.log(y); // 输出: 20 } console.log(y); // 报错: y is not defined(因为 let 是块级作用域) } example();
const
- 作用域:块级作用域(block-scoped),与
let相同。 - 变量提升:与
let相同,存在暂时性死区。 - 重复声明:不允许在同一作用域内重复声明。
- 赋值特性:
const声明的变量必须初始化,且不能重新赋值。- 如果变量是对象或数组,其内部属性或元素可以修改,但不能重新赋值整个变量。
- 示例:javascript
const z = 30; z = 40; // 报错: Assignment to constant variable const obj = { name: "Alice" }; obj.name = "Bob"; // 允许修改属性 console.log(obj); // 输出: { name: "Bob" } obj = { name: "Charlie" }; // 报错: Assignment to constant variable
对比总结
| 特性 | var | let | const |
|---|---|---|---|
| 作用域 | 函数作用域 | 块级作用域 | 块级作用域 |
| 变量提升 | 是(值为undefined) | 是(暂时性死区) | 是(暂时性死区) |
| 重复声明 | 允许 | 不允许 | 不允许 |
| 重新赋值 | 允许 | 允许 | 不允许 |
| 初始化要求 | 不需要 | 不需要 | 必须初始化 |
使用建议
- 优先使用
const:- 如果变量的值不会改变,使用
const可以避免意外修改。
- 如果变量的值不会改变,使用
- 需要重新赋值时使用
let:- 如果变量的值需要改变,使用
let。
- 如果变量的值需要改变,使用
- 避免使用
var:var的函数作用域和变量提升容易导致 bug,现代 JavaScript 中推荐使用let和const。
示例对比
// var
var a = 1;
var a = 2; // 允许重复声明
console.log(a); // 输出: 2
// let
let b = 1;
let b = 2; // 报错: Identifier 'b' has already been declared
// const
const c = 1;
c = 2; // 报错: Assignment to constant variable通过理解这些区别,可以更好地选择适合的变量声明方式,避免潜在的问题。
ES中padStart()、padEnd()
在 ECMAScript (ES) 中,padStart() 和 padEnd() 是字符串对象的方法,用于在字符串的开头或结尾填充指定的字符,直到字符串达到指定的长度。
padStart()
padStart() 方法会在字符串的开头填充指定的字符,直到字符串达到指定的长度。
语法:
str.padStart(targetLength [, padString])targetLength:目标长度。如果当前字符串长度小于该值,则在开头填充字符,直到字符串长度达到该值。padString(可选):用于填充的字符。默认为空格 ()。
示例:
const str = '5';
console.log(str.padStart(3, '0')); // 输出: "005"
console.log(str.padStart(5, '*')); // 输出: "****5"padEnd()
padEnd() 方法会在字符串的结尾填充指定的字符,直到字符串达到指定的长度。
语法:
str.padEnd(targetLength [, padString])targetLength:目标长度。如果当前字符串长度小于该值,则在结尾填充字符,直到字符串长度达到该值。padString(可选):用于填充的字符。默认为空格 ()。
示例:
const str = '5';
console.log(str.padEnd(3, '0')); // 输出: "500"
console.log(str.padEnd(5, '*')); // 输出: "5****"总结
padStart()用于在字符串开头填充字符。padEnd()用于在字符串结尾填充字符。- 如果填充字符 (
padString) 未提供,默认使用空格填充。 - 如果目标长度 (
targetLength) 小于或等于字符串的当前长度,则返回原字符串。
这两个方法在处理字符串对齐、格式化输出等场景中非常有用。