JavaScript Proxy 和 Reflect
2025年6月8日 19:03
一、Proxy 基本概念 1. 什么是 Proxy Proxy 是 ES6 引入的元编程特性,用于创建一个对象的代理,从而可以拦截和自定义对象的基本操作。 2. 核心术语 target:被代理的目标对
// 基本用法
const name = 'Alice';
const greeting = `Hello, ${name}!`; // "Hello, Alice!"
// 多行字符串
const multiLine = `
This is
a multi-line
string
`;
// 标签模板
function tag(strings, ...values) {
console.log(strings); // ["Hello ", "!"]
console.log(values); // ["Alice"]
return strings[0] + values[0].toUpperCase() + strings[1];
}
const result = tag`Hello ${name}!`; // "Hello ALICE!"
this
// 基本语法
const add = (a, b) => a + b;
// 单参数可省略括号
const square = x => x * x;
// 无参数需要括号
const sayHi = () => console.log('Hi');
// 返回对象需要用括号包裹
const makePerson = (name, age) => ({ name, age });
// this 绑定示例
const counter = {
count: 0,
increment: function() {
setInterval(() => {
this.count++; // 正确绑定this
console.log(this.count);
}, 1000);
}
};
function greet(name = 'Guest', greeting = 'Hello') {
return `${greeting}, ${name}!`;
}
console.log(greet()); // "Hello, Guest!"
function sum(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 6
const person = { name: 'John', age: 30, city: 'New York' };
const { name, age } = person;
console.log(name, age); // "John" 30
// 别名
const { name: personName } = person;
console.log(personName); // "John"
// 默认值
const { country = 'USA' } = person;
console.log(country); // "USA"
const numbers = [1, 2, 3];
const [first, second] = numbers;
console.log(first, second); // 1 2
// 跳过元素
const [,, third] = numbers;
console.log(third); // 3
// 剩余元素
const [head, ...tail] = numbers;
console.log(tail); // [2, 3]
const name = 'Alice';
const age = 25;
const person = { name, age }; // { name: 'Alice', age: 25 }
const obj = {
// 传统写法
sayHello: function() {},
// 简写写法
sayHi() {},
// 箭头函数
sayBye: () => {}
};
const propKey = 'name';
const obj = {
[propKey]: 'John',
[`get${propKey}`]() {
return this[propKey];
}
};
console.log(obj.getName()); // "John"
const arr = [1, 2, 3];
console.log(arr.includes(2)); // true
console.log(arr.includes(4)); // false
// 与indexOf的区别
console.log([NaN].includes(NaN)); // true
console.log([NaN].indexOf(NaN) !== -1); // false
console.log(2 ** 3); // 8
console.log(Math.pow(2, 3)); // 8
// 与Math.pow()的区别
console.log((-2) ** 3); // -8
console.log(Math.pow(-2, 3)); // -8
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('Error:', error);
}
}
const obj = { a: 1, b: 2, c: 3 };
console.log(Object.values(obj)); // [1, 2, 3]
console.log(Object.entries(obj)); // [["a", 1], ["b", 2], ["c", 3]]
// 与for...in的区别
for (const [key, value] of Object.entries(obj)) {
console.log(`${key}: ${value}`);
}
console.log('5'.padStart(2, '0')); // "05"
console.log('12'.padStart(2, '0')); // "12"
console.log('abc'.padEnd(5, '*')); // "abc**"
function foo(
param1,
param2, // 允许尾逗号
) {
// ...
}
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// 覆盖属性
const obj3 = { ...obj1, a: 3 }; // { a: 3, b: 2 }
// 浅拷贝
const obj4 = { ...obj1 };
console.log(obj4 === obj1); // false
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error(error))
.finally(() => console.log('Request completed'));
const re = /(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})/;
const match = re.exec('2023-05-15');
console.log(match.groups.year); // "2023"
const re = /foo.bar/s;
console.log(re.test('foo\nbar')); // true
console.log(/(?<=\$)\d+/.exec('$100')[0]); // "100" (匹配$后的数字)
console.log(/(?<!\$)\d+/.exec('€100')[0]); // "100" (匹配前面不是$的数字)
const arr = [1, [2, [3]]];
console.log(arr.flat()); // [1, 2, [3]]
console.log(arr.flat(2)); // [1, 2, 3]
const sentences = ["Hello world", "Goodbye universe"];
const words = sentences.flatMap(sentence => sentence.split(' '));
console.log(words); // ["Hello", "world", "Goodbye", "universe"]
const entries = [['name', 'John'], ['age', 30]];
const obj = Object.fromEntries(entries);
console.log(obj); // { name: "John", age: 30 }
// 与Object.entries()配合使用
const newObj = Object.fromEntries(
Object.entries(obj).map(([key, value]) => [key, String(value)])
);
const str = ' hello ';
console.log(str.trimStart()); // "hello "
console.log(str.trimEnd()); // " hello"
try {
// ...
} catch { // 不需要指定error参数
console.log('An error occurred');
}
const user = { profile: { name: 'John' } };
// 传统写法
const name = user && user.profile && user.profile.name;
// 可选链写法
const name = user?.profile?.name;
// 函数调用
user.sayHi?.(); // 如果sayHi存在则调用
// 数组访问
const firstItem = arr?.[0];
const value = null ?? 'default'; // "default"
const value2 = 0 ?? 'default'; // 0 (与||不同)
// 与||的区别
console.log(0 || 'default'); // "default"
console.log('' || 'default'); // "default"
console.log(false || 'default'); // "default"
// 按需加载模块
button.addEventListener('click', async () => {
const module = await import('./module.js');
module.doSomething();
});
const bigNum = 9007199254740991n; // 字面量加n
const anotherBigNum = BigInt("9007199254740991");
console.log(bigNum + anotherBigNum); // 18014398509481982n
// 不能与Number混合运算
console.log(bigNum + 1); // TypeError
// 逻辑或赋值
let a = false;
a ||= true; // a = a || true
// 逻辑与赋值
let b = true;
b &&= false; // b = b && false
// 空值合并赋值
let c = null;
c ??= 'default'; // c = c ?? 'default'
const str = 'hello world';
console.log(str.replaceAll('l', 'x')); // "hexxo worxd"
// 之前需要正则表达式
console.log(str.replace(/l/g, 'x')); // "hexxo worxd"
const promises = [
Promise.reject('Error 1'),
Promise.resolve('Success 1'),
Promise.reject('Error 2')
];
Promise.any(promises)
.then(result => console.log(result)) // "Success 1"
.catch(errors => console.log(errors));
const billion = 1_000_000_000; // 更易读
console.log(billion === 1000000000); // true
class Counter {
count = 0; // 实例字段
increment = () => { // 箭头函数方法
this.count++;
};
static version = '1.0'; // 静态字段
}
class Person {
#name; // 私有字段
constructor(name) {
this.#name = name;
}
#privateMethod() { // 私有方法
return `Hello, ${this.#name}`;
}
greet() {
console.log(this.#privateMethod());
}
}
const person = new Person('John');
person.greet(); // "Hello, John"
// person.#name; // SyntaxError
class Translator {
static translations = {
yes: 'ja',
no: 'nein'
};
static englishWords = [];
static germanWords = [];
static { // 静态初始化块
for (const [english, german] of Object.entries(this.translations)) {
this.englishWords.push(english);
this.germanWords.push(german);
}
}
}
// 在模块顶层使用await
const data = await fetchData();
console.log(data);
// 之前需要包装在async函数中
(async () => {
const data = await fetchData();
console.log(data);
})();
const numbers = [1, 2, 3, 4, 3, 2, 1];
console.log(numbers.findLast(n => n > 2)); // 3 (最后一个满足条件的元素)
console.log(numbers.findLastIndex(n => n > 2)); // 4 (索引)
#!/usr/bin/env node
// 现在ES标准正式支持Shebang语法
console.log('Hello from CLI tool');
const weakMap = new WeakMap();
const key = Symbol('privateData');
const obj = {};
weakMap.set(key, 'secret');
weakMap.set(obj, 'other secret');
console.log(weakMap.get(key)); // "secret"
console.log(weakMap.get(obj)); // "other secret"
版本 | 重要特性 |
---|---|
ES6 | 类、模块、箭头函数、模板字符串、解构、Promise、let/const |
ES2016 | includes()、指数运算符 |
ES2017 | async/await、Object.values/entries、字符串填充 |
ES2018 | 对象扩展运算符、Promise.finally、正则增强 |
ES2019 | Array.flat/flatMap、Object.fromEntries、trimStart/End |
ES2020 | 可选链、空值合并、动态导入、BigInt |
ES2021 | 逻辑赋值、replaceAll、Promise.any、数字分隔符 |
ES2022 | 类字段、私有方法、静态块、顶层await |
ES2023 | Array.findLast、Hashbang、WeakMap Symbol键 |