2012-03-20 29 views
17

có cách nào để tôi có thể thực hiện eval() trên một phạm vi cụ thể (nhưng KHÔNG phải toàn cục)?Chỉ định phạm vi cho eval() trong JavaScript?

ví dụ, đoạn mã sau không làm việc (một là undefined trên báo cáo kết quả thứ hai) bởi vì họ đang ở trên phạm vi khác nhau:

eval(var a = 1); 
eval(alert(a)); 

Nếu có thể, tôi muốn tạo ra một phạm vi khi đang bay . ví dụ (cú pháp chắc chắn là sai, nhưng chỉ để minh họa ý tưởng)

var scope1; 
var scope2; 
with scope1{ 
    eval(var a = 1); eval(alert(a)); // this will alert 1 
} 
with scope2{ 
    eval(var a = 1); eval(a++); eval(alert(a)); // this will alert 2 
} 
with scope1{ 
    eval(a += 2); eval(alert(a)); // this will alert 3 because a is already defined in scope1 
} 

Bất kỳ ý tưởng nào về cách đạt được điều gì đó như thế này? Cảm ơn!

+0

Trong trường hợp ai đó vẫn quan tâm, tôi chỉ đăng một câu trả lời ở đây http://stackoverflow.com/a/43306962/1758245 –

Trả lời

13

bạn có thể sử dụng "use strict" để chứa mã được đánh giá trong chính bản thân eval.

Thứ hai, eval mã chế độ nghiêm ngặt không giới thiệu các biến mới vào phạm vi xung quanh. Trong mã thông thường eval("var x;") giới thiệu một biến số x vào hàm xung quanh hoặc phạm vi toàn cục. Điều này có nghĩa rằng, trong một hàm có chứa một cuộc gọi đến eval, mỗi tên không đề cập đến một đối số hoặc biến cục bộ phải được ánh xạ tới một định nghĩa cụ thể trong thời gian chạy (vì eval có thể đã giới thiệu một biến mới sẽ ẩn biến bên ngoài). Trong chế độ nghiêm ngặt eval tạo ra các biến chỉ cho mã đang được đánh giá, vì vậy eval không thể ảnh hưởng đến việc một tên dùng để chỉ một biến bên ngoài hoặc một số biến địa phương

var x = 17;          //a local variable 
var evalX = eval("'use strict'; var x = 42; x"); //eval an x internally 
assert(x === 17);         //x is still 17 here 
assert(evalX === 42);        //evalX takes 42 from eval'ed x 

Nếu một hàm được khai báo với "sử dụng nghiêm ngặt ", mọi thứ trong nó sẽ được thực hiện ở chế độ nghiêm ngặt. sau đây sẽ làm tương tự như trên:

function foo(){ 
    "use strict"; 

    var x = 17; 
    var evalX = eval("var x = 42; x"); 
    assert(x === 17); 
    assert(evalX === 42); 
} 
+1

Như một lưu ý phụ, với 'sử dụng nghiêm ngặt' ** với ** sẽ gây ra một ngoại lệ. Trích dẫn: với() {} báo cáo đã chết khi chế độ nghiêm ngặt được kích hoạt - trong thực tế nó thậm chí xuất hiện như là một lỗi cú pháp. Nguồn: http://ejohn.org/blog/ecmascript-5-strict-mode-json-and-more/ –

+0

Nó không hoạt động đối với tôi. Tôi đã thử nó với Chrome – Zo72

+0

@Joseph người mơ mộng Nó không làm việc cho tôi. Tôi đã thử với Chrome. Trình duyệt nào hỗ trợ điều này? – Zo72

1

Bạn có thể nhìn vào các dự án vm-browserify, mà sẽ được sử dụng kết hợp với browserify.

Nó hoạt động bằng cách tạo s và eval nhập mã trong đó . Mã này thực sự khá đơn giản, vì vậy bạn có thể điều chỉnh ý tưởng cơ bản cho các mục đích của riêng bạn nếu bạn không muốn sử dụng chính thư viện đó.

4

Tạo các biến bạn muốn tồn tại trong phạm vi của bạn dưới dạng biến cục bộ trong một hàm. Sau đó, từ hàm đó, trả về một hàm được định nghĩa cục bộ có một đối số và gọi eval trên đó. Ví dụ của eval sẽ sử dụng phạm vi hàm chứa của nó, được lồng trong phạm vi chức năng cấp cao nhất của bạn. Mỗi lời gọi hàm cấp cao nhất tạo ra một phạm vi mới với một thể hiện mới của hàm eval. Để giữ cho mọi thứ động, bạn thậm chí có thể sử dụng một cuộc gọi đến eval trong hàm mức cao nhất để khai báo các biến sẽ nằm trong phạm vi đó.

Ví dụ mã:

function makeEvalContext (declarations) 
{ 
    eval(declarations); 
    return function (str) { eval(str); } 
} 

eval1 = makeEvalContext ("var x;"); 
eval2 = makeEvalContext ("var x;"); 

eval1("x = 'first context';"); 
eval2("x = 'second context';"); 
eval1("window.alert(x);"); 
eval2("window.alert(x);"); 

https://jsfiddle.net/zgs73ret/

1

Đây là một dòng 20 hoặc lâu hơn lớp JS mà thực hiện một bối cảnh mở rộng sử dụng eval trong một phạm vi từ vựng:

// Scope class 
 
// aScope.eval(str) -- eval a string within the scope 
 
// aScope.newNames(name...) - adds vars to the scope 
 
function Scope() { 
 
    "use strict"; 
 
    this.names = []; 
 
    this.eval = function(s) { 
 
    return eval(s); 
 
    }; 
 
} 
 

 
Scope.prototype.newNames = function() { 
 
    "use strict"; 
 
    var names = [].slice.call(arguments); 
 
    var newNames = names.filter((x)=> !this.names.includes(x)); 
 

 
    if (newNames.length) { 
 
    var i, len; 
 
    var totalNames = newNames.concat(this.names); 
 
    var code = "(function() {\n"; 
 

 
    for (i = 0, len = newNames.length; i < len; i++) { 
 
     code += 'var ' + newNames[i] + ' = null;\n'; 
 
    } 
 
    code += 'return function(str) {return eval(str)};\n})()'; 
 
    this.eval = this.eval(code); 
 
    this.names = totalNames; 
 
    } 
 
} 
 

 

 
// LOGGING FOR EXAMPLE RUN 
 
function log(s, eval, expr) { 
 
\t s = '<span class="remark">' + String(s); 
 
    if (expr) { 
 
    s += ':\n<b>' + expr + '</b> --> '; 
 
    } 
 
    s += '</span>'; 
 
    if (expr) { 
 
    try { 
 
     s += '<span class="result">' + JSON.stringify(eval(expr)) + '</span>'; 
 
    } catch (err) { 
 
     s += '<span class="error">' + err.message + '</span>'; 
 
    } 
 
    } 
 
    document.body.innerHTML += s + '\n\n'; 
 
} 
 
document.body.innerHTML = ''; 
 

 

 
// EXAMPLE RUN 
 
var scope = new Scope(); 
 
log("Evaluating a var statement doesn't change the scope but newNames does (should return undefined)", scope.eval, 'var x = 4') 
 
log("X in the scope object should raise 'x not defined' error", scope.eval, 'x'); 
 
log("X in the global scope should raise 'x not defined' error", eval, 'x'); 
 
log("Adding X and Y to the scope object"); 
 
scope.newNames('x', 'y'); 
 
log("Assigning x and y", scope.eval, 'x = 3; y = 4'); 
 
log("X in the global scope should still raise 'x not defined' error", eval, 'x'); 
 
log("X + Y in the scope object should be 7", scope.eval, 'x + y'); 
 
log("X + Y in the global scope should raise 'x not defined' error", eval, 'x + y');
.remark { 
 
    font-style: italic; 
 
} 
 

 
.result, .error { 
 
    font-weight: bold; 
 
} 
 

 
.error { 
 
    color: red; 
 
}
<body style='white-space: pre'></body>

Các vấn đề liên quan