JavaScript全局函数研究_手写模仿实现:eval、isFinite、isNaN、parseFloat、parseInt
JavaScript提供了一系列全局函数,用于在不同的场景下处理数据。这些函数包括eval
、isFinite
、isNaN
、parseFloat
和parseInt
等。理解这些函数的工作原理,有助于我们更深入地掌握JavaScript的核心机制。本文将逐一介绍这些全局函数的作用,并尝试手写模仿它们的实现,深入剖析其内部逻辑。
一、eval()
1. 基础介绍
eval()
函数接收一个字符串作为参数,将其作为JavaScript代码执行。它可以动态地执行字符串形式的代码,这在某些动态场景下非常有用。然而,由于安全和性能问题,通常不建议使用eval()
。
2. 语法
eval(string)
- string:要执行的字符串代码。
3. 示例代码
const code = 'console.log("Hello, World!");';
eval(code); // 输出: Hello, World!
4. 手写模仿实现
由于eval()
是JavaScript引擎内置的解析器功能,无法完全手写实现其功能。但我们可以模拟eval()
的一些简单场景,例如执行基本的数学表达式解析。
示例:简单的数学表达式求值
function simpleEval(expr) {
// 只允许数字和基本运算符,防止安全问题
if (/^[\d+\-*/\s()]+$/.test(expr)) {
return new Function(`return ${expr}`)();
} else {
throw new Error('Invalid expression');
}
}
console.log(simpleEval('2 + 3 * (4 - 1)')); // 输出: 11
注意:上面的实现使用了new Function()
,它与eval()
类似,也存在安全隐患。在生产环境中,应避免执行来自不可信来源的代码。
5. 安全与性能考虑
- 安全性:
eval()
可能执行恶意代码,导致安全漏洞。 - 性能:
eval()
在执行时需要调用解释器,可能会降低性能。 - 替代方案:通常可以通过其他方式实现同样的功能,例如使用对象映射、函数调用等。
二、isFinite()
1. 基础介绍
isFinite()
函数用于判断一个值是否为有限数值。当参数转换为数字类型后,如果是有限数字,则返回true
,否则返回false
。
2. 语法
isFinite(value)
- value:要检测的值。
3. 示例代码
console.log(isFinite(100)); // 输出: true
console.log(isFinite('200')); // 输出: true(字符串会被转换为数字)
console.log(isFinite(Infinity)); // 输出: false
console.log(isFinite(NaN)); // 输出: false
4. 手写模仿实现
function myIsFinite(value) {
const num = Number(value);
return typeof num === 'number' && !isNaN(num) && num !== Infinity && num !== -Infinity;
}
console.log(myIsFinite(100)); // 输出: true
console.log(myIsFinite('200')); // 输出: true
console.log(myIsFinite(Infinity)); // 输出: false
console.log(myIsFinite(NaN)); // 输出: false
5. 实现原理
- 首先,将传入的值转换为数字类型。
- 检查类型是否为
number
,并排除NaN
、Infinity
、-Infinity
。
三、isNaN()
1. 基础介绍
isNaN()
函数用于判断一个值是否为NaN
(非数字值)。当参数转换为数字后,如果结果是NaN
,则返回true
,否则返回false
。
2. 语法
isNaN(value)
- value:要检测的值。
3. 示例代码
console.log(isNaN(NaN)); // 输出: true
console.log(isNaN('hello')); // 输出: true('hello'转换为数字是NaN)
console.log(isNaN(123)); // 输出: false
console.log(isNaN('456')); // 输出: false
4. 手写模仿实现
function myIsNaN(value) {
const num = Number(value);
return num !== num;
}
console.log(myIsNaN(NaN)); // 输出: true
console.log(myIsNaN('hello')); // 输出: true
console.log(myIsNaN(123)); // 输出: false
console.log(myIsNaN('456')); // 输出: false
5. 实现原理
- 将值转换为数字。
- 利用
NaN
不等于自身的特性,即NaN !== NaN
为true
。
注意:ES6引入了Number.isNaN()
,它更为严格,只在参数为NaN
时返回true
。
console.log(Number.isNaN('hello')); // 输出: false
四、parseFloat()
1. 基础介绍
parseFloat()
函数解析一个字符串参数,并返回一个浮点数。如果字符串的第一个字符不能被转换为数字,则返回NaN
。
2. 语法
parseFloat(string)
- string:要解析的字符串。
3. 示例代码
console.log(parseFloat('3.14')); // 输出: 3.14
console.log(parseFloat('10e2')); // 输出: 1000
console.log(parseFloat(' -5.5 ')); // 输出: -5.5
console.log(parseFloat('abc')); // 输出: NaN
4. 手写模仿实现
function myParseFloat(str) {
const regex = /^\s*([+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?)\s*/;
const match = str.match(regex);
if (match) {
return Number(match[1]);
} else {
return NaN;
}
}
console.log(myParseFloat('3.14')); // 输出: 3.14
console.log(myParseFloat('10e2')); // 输出: 1000
console.log(myParseFloat(' -5.5 ')); // 输出: -5.5
console.log(myParseFloat('abc')); // 输出: NaN
5. 实现原理
- 使用正则表达式匹配浮点数格式。
- 提取匹配的数值字符串并转换为数字。
- 处理前导和后续的空白字符。
五、parseInt()
1. 基础介绍
parseInt()
函数解析一个字符串参数,并返回一个指定基数的整数。如果字符串的第一个字符不能被转换为数字,则返回NaN
。
2. 语法
parseInt(string, [radix])
- string:要解析的字符串。
- radix(可选):表示要解析的数字的基数(2 ~ 36)。
3. 示例代码
console.log(parseInt('42')); // 输出: 42
console.log(parseInt('1010', 2)); // 输出: 10(二进制)
console.log(parseInt('ff', 16)); // 输出: 255(十六进制)
console.log(parseInt('0x10')); // 输出: 16
console.log(parseInt('abc')); // 输出: NaN
4. 手写模仿实现
function myParseInt(str, radix) {
str = String(str).trim();
radix = radix || 0;
const regexHex = /^[-+]?0[xX][\dA-Fa-f]+$/;
const regexOct = /^[-+]?0[oO][0-7]+$/;
const regexBin = /^[-+]?0[bB][01]+$/;
if (radix === 0) {
if (regexHex.test(str)) radix = 16;
else if (regexOct.test(str)) radix = 8;
else if (regexBin.test(str)) radix = 2;
else radix = 10;
}
const regex = new RegExp(`^[-+]?([\\dA-Za-z]+)`);
const match = str.match(regex);
if (match) {
const numStr = match[0];
return Number.parseInt(numStr, radix);
} else {
return NaN;
}
}
console.log(myParseInt('42')); // 输出: 42
console.log(myParseInt('1010', 2)); // 输出: 10
console.log(myParseInt('ff', 16)); // 输出: 255
console.log(myParseInt('0x10')); // 输出: 16
console.log(myParseInt('abc')); // 输出: NaN
5. 实现原理
- 将输入转换为字符串并去除空白字符。
- 处理
radix
参数,确定进制。 - 使用正则表达式提取有效的数字部分。
- 利用
Number.parseInt()
进行数值转换。
注意:在ECMAScript规范中,parseInt()
在radix
为0
或未提供时,会根据字符串内容自动判断进制。
注意事项
- 安全性:避免使用
eval()
或new Function()
执行不可信的代码。 - 类型转换:
isFinite()
和isNaN()
会进行隐式类型转换,需要注意输入类型。 - 进制处理:
parseInt()
的radix
参数非常重要,可能影响结果,需要明确指定。
参考资料
- MDN JavaScript eval()
- MDN JavaScript isFinite()
- MDN JavaScript isNaN()
- MDN JavaScript parseFloat()
- MDN JavaScript parseInt()