Eval
eval可以执行一段 JS 代码片段:
eval("console.log('hello world')");
eval可以执行多行语句,返回的结果时最后一条语句的结果:
let result = eval("let i=0;++i;");
console.log(result);
// 1
eval的词法环境包含于当前的词法环境,因此可以访问外部变量:
let name = 'Jack';
eval("console.log('hello ' + name)");
// hello Jack
甚至是修改外部变量:
let name = 'Jack';
let age = 18;
eval(`
age++;
console.log('hello ' + name + ' ' + age);
`);
// hello Jack 19
eval有自己的词法环境,外部不能访问eval内部的变量:
eval("function hello() {console.log('hello world')}");
hello();
// ReferenceError: hello is not defined
在严格模式下才生效,比如
use strict或模块中。
在现代 JS 中,一般不需要使用eval,且eval存在一个严重问题,现代 JS 一般都会使用 JS 压缩,压缩后的 JS 代码中的变量名会被重命名,如果eval中有对外部变量的读写,就可能出错。
柯里化
柯里化是一种函数转换,可以将f(a,b,c)转换为f(a)(b)(c):
function curry(fn){
return function (a){
return function (b){
return fn(a,b);
}
}
}
function add(a,b){
return a+b;
}
let curryAdd = curry(add);
console.log(curryAdd(1)(2));
有很多第三方库都提供柯里化的工具函数,比如lodash:
function add(a, b) {
return a + b;
}
let _ = require('lodash');
let curryAdd = _.curry(add);
console.log(curryAdd(1)(2));
console.log(curryAdd(1, 2));
柯里化的好处是我们可以利用其特点很容易地快速创建新的函数:
let _ = require('lodash');
function log(date, level, message){
console.log(`${date} [${level}]: ${message}`);
}
let curryLog = _.curry(log);
let todayLog = curryLog(new Date());
let todayInfo = todayLog('INFO');
let todayError = todayLog('ERROR');
todayInfo('hello world');
todayError('hello world');
// Mon Apr 20 2026 15:36:33 GMT+0800 (中国标准时间) [INFO]: hello world
// Mon Apr 20 2026 15:36:33 GMT+0800 (中国标准时间) [ERROR]: hello world
如果不想使用第三方库,要手动实现多参数的柯里化:
function curry(fn){
return function curried(args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function (args2) {
return curried.apply(this, args.concat(args2));
}
}
}
}
function add(a, b, c) {
return a + b + c;
}
let curryAdd = curry(add);
console.log(curryAdd(1)(2)(3));
console.log(curryAdd(1, 2)(3));
console.log(curryAdd(1, 2, 3));
引用类型
会出现丢失this的情况:
let user = {
_name: 'Mike',
getName() {
return this._name;
}
}
console.log(user.getName());
// Mike
let getName = user.getName;
console.log(getName());
// TypeError: Cannot read properties of undefined (reading '_name')
直接调用对象方法没有问题,但如果将对象方法赋值给额外变量,再调用变量就会报错,因为此时this是undefined。
原因是使用.操作符获取到的对象方法user.getName返回的其实是一个 JS 使用的内部类型,该类型包含三部分内容:
(user, "getName", true)
因此获取引用对象后直接调用时可以获取到正确的this:
user.getName()
但如果赋值,结果会变成对象方法,this对应的user对象被丢弃。
可以使用func.bind解决这个问题:
let user = {
_name: 'Mike',
getName() {
return this._name;
}
}
console.log(user.getName());
// Mike
let getName = user.getName.bind(user);
console.log(getName());
The End.
本文的完整示例代码可以从获取。

文章评论