元编程是指编写能够操作其他程序(或自身)作为数据的程序。
// 运行时检查和操作对象结构
const obj = { x: 1, y: 2 };
// 反射 API
console.log(typeof obj); // "object"
console.log(Array.isArray(obj)); // false
console.log(Object.keys(obj)); // ["x", "y"]
console.log(Reflect.has(obj, "x")); // true
console.log(Reflect.get(obj, "x")); // 1
const target = {
name: "John",
age: 30,
};
const handler = {
// 拦截属性读取
get(target, property, receiver) {
console.log(`Getting property "${property}"`);
if (property === "fullName") {
return `${target.name} Doe`;
}
return Reflect.get(...arguments);
},
// 拦截属性设置
set(target, property, value, receiver) {
console.log(`Setting property "${property}" to "${value}"`);
if (property === "age" && (typeof value !== "number" || value < 0)) {
throw new Error("Age must be a positive number");
}
return Reflect.set(...arguments);
},
// 拦截属性检查
has(target, property) {
console.log(`Checking if property "${property}" exists`);
return Reflect.has(...arguments);
},
// 拦截属性删除
deleteProperty(target, property) {
console.log(`Deleting property "${property}"`);
if (property === "name") {
throw new Error("Cannot delete name property");
}
return Reflect.deleteProperty(...arguments);
},
};
const proxy = new Proxy(target, handler);
// 使用代理
console.log(proxy.name); // "Getting property "name"", "John"
console.log(proxy.fullName); // "Getting property "fullName"", "John Doe"
proxy.age = 25; // "Setting property "age" to "25""
console.log("age" in proxy); // "Checking if property "age" exists", true
const exhaustiveHandler = {
// 基本操作
get(target, prop, receiver) {},
set(target, prop, value, receiver) {},
has(target, prop) {},
deleteProperty(target, prop) {},
// 函数调用
apply(target, thisArg, argumentsList) {},
construct(target, argumentsList, newTarget) {},
// 原型操作
getPrototypeOf(target) {},
setPrototypeOf(target, prototype) {},
isExtensible(target) {},
preventExtensions(target) {},
// 属性描述符
getOwnPropertyDescriptor(target, prop) {},
defineProperty(target, prop, descriptor) {},
// 枚举
ownKeys(target) {},
};
// 使用示例
function sum(a, b) {
return a + b;
}
const sumProxy = new Proxy(sum, {
apply(target, thisArg, argumentsList) {
console.log(`Called sum with arguments: ${argumentsList}`);
const result = Reflect.apply(...arguments);
console.log(`Result: ${result}`);
return result;
},
});
sumProxy(2, 3); // Called sum with arguments: 2,3 → Result: 5
const obj = { x: 1 };
// Reflect 方法对应 Proxy 拦截器
console.log(Reflect.get(obj, "x")); // 对应 get
console.log(Reflect.set(obj, "y", 2)); // 对应 set
console.log(Reflect.has(obj, "x")); // 对应 has
console.log(Reflect.deleteProperty(obj, "x")); // 对应 deleteProperty
console.log(Reflect.getPrototypeOf(obj)); // 对应 getPrototypeOf
console.log(Reflect.setPrototypeOf(obj, {})); // 对应 setPrototypeOf
console.log(Reflect.isExtensible(obj)); // 对应 isExtensible
console.log(Reflect.preventExtensions(obj)); // 对应 preventExtensions
console.log(Reflect.getOwnPropertyDescriptor(obj, "x")); // 对应 getOwnPropertyDescriptor
console.log(Reflect.defineProperty(obj, "z", { value: 3 })); // 对应 defineProperty
console.log(Reflect.ownKeys(obj)); // 对应 ownKeys
console.log(Reflect.construct(Array, [])); // 对应 construct
console.log(Reflect.apply(Math.max, null, [1, 2, 3])); // 对应 apply
// Symbol.iterator - 使对象可迭代
const iterableObj = {
data: [1, 2, 3, 4, 5],
[Symbol.iterator]() {
let index = 0;
const data = this.data;
return {
next() {
if (index < data.length) {
return { value: data[index++], done: false };
}
return { value: undefined, done: true };
},
// 可选:实现 return 方法以支持 break、throw 等
return() {
console.log("Iteration stopped");
return { done: true };
},
};
},
};
for (const item of iterableObj) {
console.log(item);
if (item === 3) break; // 触发 return 方法
}
// Symbol.asyncIterator - 异步迭代
const asyncIterable = {
async *[Symbol.asyncIterator]() {
for (let i = 0; i < 3; i++) {
await new Promise(resolve => setTimeout(resolve, 100));
yield i;
}
},
};
(async () => {
for await (const item of asyncIterable) {
console.log(item); // 0, 1, 2 (间隔100ms)
}
})();
// Symbol.hasInstance - 自定义 instanceof 行为
class MyArray {
static [Symbol.hasInstance](../04-javascript/instance) {
return Array.isArray(instance);
}
}
console.log([] instanceof MyArray); // true
console.log({} instanceof MyArray); // false
// Symbol.toPrimitive - 自定义类型转换
const temperature = {
value: 25,
unit: "C",
[Symbol.toPrimitive](../04-javascript/hint) {
switch (hint) {
case "string":
return `${this.value}°${this.unit}`;
case "number":
return this.unit === "C" ? this.value : ((this.value - 32) * 5) / 9;
default: // 'default'
return this.value;
}
},
};
console.log(String(temperature)); // "25°C"
console.log(+temperature); // 25
console.log(temperature + 5); // 30
// Symbol.toStringTag - 自定义 Object.prototype.toString 返回值
class MyClass {
get [Symbol.toStringTag]() {
return "MyClass";
}
}
const obj = new MyClass();
console.log(Object.prototype.toString.call(obj)); // "[object MyClass]"
// Symbol.species - 控制衍生对象的构造函数
class MyArray extends Array {
static get [Symbol.species]() {
return Array; // 让 map、filter 等方法返回普通数组
}
}
const myArray = new MyArray(1, 2, 3);
const mapped = myArray.map(x => x * 2);
console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array); // true
// Symbol.match, Symbol.replace, Symbol.search, Symbol.split
class CaseInsensitiveString {
constructor(str) {
this.value = str;
}
[Symbol.match](../04-javascript/pattern) {
return this.value.toLowerCase().match(pattern.toLowerCase());
}
[Symbol.replace](pattern, replacement) {
return this.value.toLowerCase().replace(pattern.toLowerCase(), replacement);
}
[Symbol.search](../04-javascript/pattern) {
return this.value.toLowerCase().search(pattern.toLowerCase());
}
[Symbol.split](../04-javascript/separator) {
return this.value.toLowerCase().split(separator.toLowerCase());
}
}
const cis = new CaseInsensitiveString("Hello World");
console.log(cis.match("hello")); // ['hello']
console.log(cis.replace("world", "Universe")); // 'hello Universe'
console.log(cis.search("WORLD")); // 6
console.log(cis.split(" ")); // ['hello', 'world']
// 不可配置、不可写、不可枚举的属性
const secureObj = {};
Object.defineProperties(secureObj, {
// 只读常量
VERSION: {
value: "1.0.0",
writable: false,
enumerable: true,
configurable: false,
},
// 私有属性
_secret: {
value: "sensitive data",
writable: false,
enumerable: false,
configurable: false,
},
// 带验证的访问器属性
age: {
get() {
return this._age;
},
set(value) {
if (value < 0 || value > 150) {
throw new Error("Invalid age");
}
this._age = value;
},
enumerable: true,
configurable: false,
},
});
// 对象密封
Object.seal(secureObj); // 不能添加/删除属性,可以修改现有属性
Object.freeze(secureObj); // 完全冻结,不能修改
// 创建多层代理
function createObservable(target, onChange) {
return new Proxy(target, {
get(target, property) {
const value = target[property];
// 如果值是对象,递归创建代理
if (value && typeof value === "object" && !Array.isArray(value)) {
return createObservable(value, onChange);
}
return value;
},
set(target, property, value) {
const oldValue = target[property];
target[property] = value;
// 触发回调
onChange({
target,
property,
oldValue,
newValue: value,
type: oldValue === undefined ? "add" : "update",
});
return true;
},
deleteProperty(target, property) {
const oldValue = target[property];
const deleted = Reflect.deleteProperty(target, property);
if (deleted) {
onChange({
target,
property,
oldValue,
type: "delete",
});
}
return deleted;
},
});
}
const data = { user: { name: "John", address: { city: "NYC" } } };
const observable = createObservable(data, change => {
console.log("Change detected:", change);
});
observable.user.name = "Jane"; // 触发回调
observable.user.address.city = "LA"; // 嵌套对象也会触发
// 添加元数据到函数
function addMetadata(fn, metadata) {
return Object.assign(fn, {
metadata,
// 链式调用支持
withMetadata(newMetadata) {
return addMetadata(fn, { ...metadata, ...newMetadata });
},
});
}
// 使用示例
const processData = addMetadata(
function (data) {
return data * 2;
},
{ version: "1.0", author: "John", tags: ["math", "transformation"] }
);
console.log(processData.metadata); // { version: '1.0', author: 'John', tags: [...] }
console.log(processData(5)); // 10
// 添加验证元数据
function validateParams(fn, paramTypes) {
const validatedFn = function (...args) {
paramTypes.forEach((type, index) => {
if (typeof args[index] !== type) {
throw new TypeError(
`Parameter ${index} should be ${type}, got ${typeof args[index]}`
);
}
});
return fn(...args);
};
// 复制函数属性
Object.setPrototypeOf(validatedFn, Object.getPrototypeOf(fn));
Object.defineProperties(validatedFn, Object.getOwnPropertyDescriptors(fn));
return validatedFn;
}
const add = validateParams((a, b) => a + b, ["number", "number"]);
console.log(add(1, 2)); // 3
console.log(add(1, "2")); // TypeError
// 函数装饰器工厂
function createDecorator(before, after) {
return function (target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function (...args) {
before?.call(this, ...args);
const result = original.apply(this, args);
after?.call(this, result, ...args);
return result;
};
return descriptor;
};
}
// 类装饰器
function logDecorator(logger = console.log) {
return function (target) {
// 记录所有方法调用
Object.getOwnPropertyNames(target.prototype).forEach(methodName => {
const original = target.prototype[methodName];
if (typeof original === "function") {
target.prototype[methodName] = function (...args) {
logger(`Calling ${methodName} with args:`, args);
const result = original.apply(this, args);
logger(`Result:`, result);
return result;
};
}
});
return target;
};
}
// 属性装饰器
function readonly(target, property, descriptor) {
descriptor.writable = false;
return descriptor;
}
// 使用示例
@logDecorator()
class Calculator {
@readonly
PI = 3.14159;
add(a, b) {
return a + b;
}
multiply(a, b) {
return a * b;
}
}
const calc = new Calculator();
console.log(calc.add(2, 3)); // 会输出日志
calc.PI = 3.14; // 静默失败(严格模式下报错)
// 简单的 ORM 实现
class Model {
constructor(data = {}) {
this._data = new Map();
this._original = new Map();
// 初始化数据
Object.entries(data).forEach(([key, value]) => {
this._data.set(key, value);
this._original.set(key, value);
});
// 创建动态访问器
return new Proxy(this, {
get(target, property) {
if (property in target) {
return target[property];
}
if (target._data.has(property)) {
return target._data.get(property);
}
return undefined;
},
set(target, property, value) {
if (property in target) {
target[property] = value;
return true;
}
target._data.set(property, value);
return true;
},
});
}
// 保存方法
save() {
// 这里应该发送到服务器
console.log("Saving:", this.toJSON());
this._original = new Map(this._data);
return Promise.resolve(this);
}
// 重置更改
reset() {
this._data = new Map(this._original);
}
// 转换为纯对象
toJSON() {
return Object.fromEntries(this._data);
}
// 检查是否有更改
get isDirty() {
if (this._data.size !== this._original.size) return true;
for (const [key, value] of this._data) {
if (this._original.get(key) !== value) return true;
}
return false;
}
}
// 使用示例
class User extends Model {
static validate(data) {
if (!data.email || !data.email.includes("@")) {
throw new Error("Invalid email");
}
return data;
}
}
const user = new User({ name: "John", email: "john@example.com" });
console.log(user.name); // "John"
user.name = "Jane";
console.log(user.isDirty); // true
await user.save();
console.log(user.isDirty); // false
// 响应式状态管理
class ReactiveStore {
constructor(initialState = {}) {
this.state = this._createReactive(initialState);
this._subscribers = new Set();
this._actions = new Map();
this._mutations = new Map();
}
_createReactive(obj, path = "") {
const self = this;
return new Proxy(obj, {
get(target, property) {
const value = target[property];
// 如果是对象,递归创建代理
if (value && typeof value === "object") {
return self._createReactive(value, path ? `${path}.${property}` : property);
}
return value;
},
set(target, property, value) {
const oldValue = target[property];
target[property] = value;
// 通知所有订阅者
self._subscribers.forEach(subscriber => {
subscriber({
path: path ? `${path}.${property}` : property,
oldValue,
newValue: value,
target: self.state,
});
});
return true;
},
});
}
// 订阅状态变化
subscribe(callback) {
this._subscribers.add(callback);
return () => this._subscribers.delete(callback);
}
// 定义 mutation
defineMutation(name, mutation) {
this._mutations.set(name, mutation);
}
// 提交 mutation
commit(name, payload) {
const mutation = this._mutations.get(name);
if (!mutation) {
throw new Error(`Mutation "${name}" not found`);
}
const oldState = JSON.parse(JSON.stringify(this.state));
mutation(this.state, payload);
// 记录变更
console.log(`Mutation: ${name}`, {
payload,
oldState,
newState: this.state,
});
}
// 定义 action(异步)
defineAction(name, action) {
this._actions.set(name, action);
}
// 分发 action
async dispatch(name, payload) {
const action = this._actions.get(name);
if (!action) {
throw new Error(`Action "${name}" not found`);
}
return await action(
{
commit: this.commit.bind(this),
state: this.state,
dispatch: this.dispatch.bind(this),
},
payload
);
}
}
// 使用示例
const store = new ReactiveStore({
user: { name: "John", age: 30 },
todos: [],
});
// 定义 mutation
store.defineMutation("SET_USER_NAME", (state, name) => {
state.user.name = name;
});
store.defineMutation("ADD_TODO", (state, todo) => {
state.todos.push(todo);
});
// 订阅变化
store.subscribe(change => {
console.log("State changed:", change);
});
// 提交 mutation
store.commit("SET_USER_NAME", "Jane");
store.commit("ADD_TODO", { id: 1, text: "Learn Meta-programming" });
// 动态 API 客户端
function createApiClient(baseURL, options = {}) {
const { timeout = 30000, interceptors = {}, defaultHeaders = {} } = options;
const client = {};
// HTTP 方法
const methods = ["get", "post", "put", "patch", "delete"];
methods.forEach(method => {
client[method] = createRequestMethod(method);
});
function createRequestMethod(method) {
return async function (url, data = null, config = {}) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), timeout);
const requestConfig = {
method: method.toUpperCase(),
headers: { ...defaultHeaders, ...config.headers },
signal: controller.signal,
...config,
};
if (data && ["post", "put", "patch"].includes(method)) {
requestConfig.body = JSON.stringify(data);
requestConfig.headers["Content-Type"] = "application/json";
}
// 请求拦截器
let request = { url: `${baseURL}${url}`, config: requestConfig };
if (interceptors.request) {
request = await interceptors.request(request);
}
try {
const response = await fetch(request.url, request.config);
clearTimeout(timeoutId);
// 响应拦截器
let processedResponse = response;
if (interceptors.response) {
processedResponse = await interceptors.response(response);
}
return processedResponse;
} catch (error) {
clearTimeout(timeoutId);
if (interceptors.error) {
return interceptors.error(error);
}
throw error;
}
};
}
// 动态端点创建
return new Proxy(client, {
get(target, endpoint) {
if (endpoint in target) {
return target[endpoint];
}
// 创建动态端点
return new Proxy(
{},
{
get(_, method) {
if (methods.includes(method)) {
return (data, config) => target[method](`/${endpoint}`, data, config);
}
// 嵌套端点:/users/123/posts
return new Proxy(
{},
{
get(_, nestedMethod) {
if (methods.includes(nestedMethod)) {
return (id, data, config) =>
target[nestedMethod](
`/${endpoint}/${id}/${method}`,
data,
config
);
}
},
}
);
},
}
);
},
});
}
// 使用示例
const api = createApiClient("https://api.example.com", {
interceptors: {
async request(request) {
const token = localStorage.getItem("token");
if (token) {
request.config.headers.Authorization = `Bearer ${token}`;
}
return request;
},
async response(response) {
if (!response.ok) {
throw new Error(`API Error: ${response.status}`);
}
return response.json();
},
},
});
// 动态 API 调用
api.users.get(); // GET /users
api.users.post({ name: "John" }); // POST /users
api.users(123).get(); // GET /users/123
api.users(123).posts.get(); // GET /users/123/posts
// 缓存代理处理程序
const proxyCache = new WeakMap();
function createOptimizedProxy(target, handler) {
if (proxyCache.has(target)) {
return proxyCache.get(target);
}
// 优化:只拦截必要的方法
const optimizedHandler = {};
// 检查哪些拦截器被定义
const proxyTraps = [
"get",
"set",
"has",
"deleteProperty",
"apply",
"construct",
"getPrototypeOf",
"setPrototypeOf",
"isExtensible",
"preventExtensions",
"getOwnPropertyDescriptor",
"defineProperty",
"ownKeys",
];
proxyTraps.forEach(trap => {
if (typeof handler[trap] === "function") {
optimizedHandler[trap] = handler[trap];
}
});
const proxy = new Proxy(target, optimizedHandler);
proxyCache.set(target, proxy);
return proxy;
}
// 使用优化后的代理
const data = {
/* 大对象 */
};
const proxy = createOptimizedProxy(data, {
get(target, prop) {
console.log("Getting:", prop);
return target[prop];
},
set() {
console.log("Setting");
return true;
},
});
// 创建安全的执行环境
function createSandbox(code, context = {}) {
// 白名单:允许访问的全局对象
const whitelist = [
"Array",
"Boolean",
"Date",
"Math",
"Number",
"Object",
"String",
"RegExp",
"JSON",
"Promise",
"Set",
"Map",
];
const allowedGlobals = whitelist.reduce((acc, name) => {
acc[name] = globalThis[name];
return acc;
}, {});
// 创建代理上下文
const sandboxContext = new Proxy(
{ ...allowedGlobals, ...context },
{
has(target, prop) {
// 不允许访问未定义的属性
if (!(prop in target)) {
throw new Error(`Access to "${prop}" is not allowed`);
}
return true;
},
get(target, prop) {
if (prop === "eval" || prop === "Function") {
throw new Error("eval and Function are not allowed");
}
if (!(prop in target)) {
throw new Error(`Access to "${prop}" is not allowed`);
}
return target[prop];
},
}
);
// 使用 Function 构造函数(而不是 eval)
const wrappedCode = `
with (sandbox) {
return (function() {
"use strict";
${code}
})();
}
`;
try {
const fn = new Function("sandbox", wrappedCode);
return fn(sandboxContext);
} catch (error) {
console.error("Sandbox error:", error);
throw error;
}
}
// 使用示例
try {
const result = createSandbox(`
const x = 10;
const y = 20;
Math.max(x, y) * 2;
`);
console.log(result); // 40
} catch (error) {
console.log("Caught error:", error.message);
}