js執(zhí)行字符串代碼的具體實現(xiàn)
一、適用場景
在業(yè)務(wù)中我們很少去將一個字符串作為代碼執(zhí)行,因為出于安全考慮,盡量不要直接在客戶端執(zhí)行用戶輸入的代碼。但是在造輪子或者框架開發(fā)中,我們需要在解析完開發(fā)者編寫的代碼后,來手動執(zhí)行這些字符串代碼。
二、具體實現(xiàn)
1. eval
eval是一個我們都知道的函數(shù),這個函數(shù)會將傳入的字符串當(dāng)做 JavaScript 代碼進行執(zhí)行。所以我們很多時候會用它來執(zhí)行字符串代碼。
例如:
const log = `console.log('11')`
eval(log)
const testCode = `
function test() {
console.log('test')
}
test()
`
eval(testCode)

注:需要注意的是,eval是在當(dāng)前上下文執(zhí)行的代碼,如果字符串中的變量與當(dāng)前上下文的變量命名沖突,就會導(dǎo)致報錯。
例如:
const test = 'test'
const testCode = `
function test() {
console.log('test')
}
test()
`
eval(testCode)

因為我們自己定義了test,而字符串中又有test函數(shù),所以就發(fā)生了沖突,出現(xiàn)報錯。
我們很難去避免字符串中的變量和當(dāng)前上下文的變量重復(fù),所以我們可以在自調(diào)用函數(shù)中執(zhí)行eval來解決這個問題。
const test = 'test'
const a = 1
const testCode = `
function test() {
console.log('test')
console.log(a)
}
test()
`
;(function () {
const a = 2
eval(testCode)
})()
這樣就沒問題了,注:這里的a打印的是2,也就是我們自調(diào)用函數(shù)作用域的a。

2. new Function()
語法:new Function(arg0, arg1, /* …, */ argN, functionBody)Function() 構(gòu)造函數(shù)創(chuàng)建 Function 對象。直接調(diào)用構(gòu)造函數(shù)可以動態(tài)創(chuàng)建函數(shù),但可能會面臨一些安全性和類似于 eval() 的性能問題(但相對較小)。然而,與具有訪問本地作用域的 eval 不同,F(xiàn)unction 構(gòu)造函數(shù)創(chuàng)建的函數(shù)僅在全局作用域中執(zhí)行。
例如:
const test = 'test'
const a = 1
const testCode = `
function test() {
console.log('test')
console.log(a)
}
test()
`
;(function () {
const a = 2
const func = new Function(testCode)
func()
})()
注:當(dāng)前的a打印的是1,也就是Function 構(gòu)造函數(shù)創(chuàng)建的函數(shù)僅在全局作用域中執(zhí)行。里面的未定義的變量會直接使用全局的變量。

如何解決這個問題?
創(chuàng)建function的時候支持傳遞參數(shù),我們可以通過參數(shù)傳遞來解決。
const test = 'test'
const a = 1
const testCode = `
function test() {
console.log('test')
console.log(a)
}
test()
`
;(function () {
const a = 2
const func = new Function('a', testCode)
func(a)
})()
我們將a傳遞作為參數(shù)傳遞到了func中,實際上func現(xiàn)在就相當(dāng)于:
function func(a) {
function test() {
console.log('test')
console.log(a)
}
test()
}

這種方式就不用但是上下文命名沖突的問題,因為代碼是在函數(shù)中執(zhí)行的,因此我們不需要在自調(diào)用函數(shù)中運行 new Function()。
并且通過這種方式我們還能接受到字符串代碼中的返回。
const test = 'test'
const sum = `return a + b`
const func = new Function('a', 'b', sum)
console.log(func(2, 3))

三、兩者差異
- eval是在當(dāng)前上下文執(zhí)行代碼,會出現(xiàn)變量命名沖突,而new Function()是在函數(shù)內(nèi)部執(zhí)行,不會出現(xiàn)沖突
- eval的作用域是當(dāng)前執(zhí)行位置的作用域,而new Function()的作用域是全局
- eval不能傳遞參數(shù),也不能接受返回值,new Function()可以傳遞參數(shù)并接收返回值
所以如果是大量的執(zhí)行字符串代碼,建議使用new Function()的方式,它更強大(比如Vue框架就使用new Function()的方式)。如果你只是偶爾使用,并且對參數(shù)、命名也沒要求,那就直接使用eval,更加簡單方便。
附:結(jié)合eval和new Function()一起實現(xiàn)
try {
const val = new Function(“要執(zhí)行的字符串”);
let eleResult = val(); // 這里必須調(diào)用val(),不然不會執(zhí)行
if (!eleResult) {
eleResult = eval(“要執(zhí)行的字符串”);
}
} catch (err) {
console.info(‘執(zhí)行字符串js出錯');
}到此這篇關(guān)于js執(zhí)行字符串代碼具體實現(xiàn)的文章就介紹到這了,更多相關(guān)js執(zhí)行字符串代碼內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
使用JavaScript實現(xiàn)小球按照貝塞爾曲線運動
要在 JavaScript 中實現(xiàn)一個按照貝塞爾曲線運動的小球,關(guān)鍵是要掌握貝塞爾公式的基本原理和實現(xiàn)方式,以及使用 JavaScript 處理動畫和物理運算,感興趣的小伙伴跟著小編一起來看看吧2024-10-10
JavaScript實現(xiàn)shuffle數(shù)組洗牌操作示例
這篇文章主要介紹了JavaScript實現(xiàn)shuffle數(shù)組洗牌操作,結(jié)合實例形式分析了javascript數(shù)組的定義、構(gòu)造、排序等相關(guān)操作技巧,需要的朋友可以參考下2019-01-01

