当前位置: 首页 > 面试题库 >

是否可以在不使用eval的情况下在JavaScript中实现动态作用域?

子车鸿运
2023-03-14
问题内容

JavaScript具有词法作用域,这意味着从函数内部访问的非局部变量在定义时将解析为该函数的父级作用域中存在的变量。这与动态作用域相反,在动态作用域中,从函数内部访问的非局部变量在调用时将解析为该函数的调用范围中存在的变量。

x=1
function g () { echo $x ; x=2 ; }
function f () { local x=3 ; g ; }
f # does this print 1, or 3?
echo $x # does this print 1, or 2?

上面的程序以词法范围的语言先打印1,然后再打印2,然后以动态范围的语言先打印3,然后再打印1。由于JavaScript具有词法范围,因此将显示1,然后显示2,如下所示:

var print = x => console.log(x);



var x = 1;



function g() {

    print(x);

    x = 2;

}



function f() {

    var x = 3;

    g();

}



f();           // prints 1



print(x);      // prints 2

尽管JavaScript不支持动态范围界定,但我们可以使用eval以下方法实现它:

var print = x => console.log(x);



var x = 1;



function g() {

    print(x);

    x = 2;

}



function f() {

    // create a new local copy of `g` bound to the current scope

    // explicitly assign it to a variable since functions can be unnamed

    // place this code in the beginning of the function - manual hoisting

    var g_ = eval("(" + String(g) + ")");

    var x = 3;

    g_();

}



f();                         // prints 3



print(x);                    // prints 1

我想知道是否存在另一种不求助于相同结果的可能方法eval

编辑: 这是我正在尝试不使用的实现eval

var print = x => console.log(x);



function Class(clazz) {

    return function () {

        var constructor;

        var Constructor = eval("(" + String(clazz) + ")");

        Constructor.apply(this, arguments);

        constructor.apply(this, arguments);

    };

}



var Rectangle = new Class(function () {

    var width, height;



    constructor = function (w, h) {

        width = w;

        height = h;

    };



    this.area = function () {

        return width * height;

    };

});



var rectangle = new Rectangle(2, 3);

print(rectangle.area());

我知道这不是一个很好的示例,但总体思路是使用动态作用域来创建闭包。我认为这种模式具有很大的潜力。


问题答案:

属性查找贯穿原型链,与动态范围非常匹配。只需传递您自己的动态范围变量环境即可使用,而不是使用Javascript的词法作用域。

// Polyfill for older browsers.  Newer ones already have Object.create.
if (!Object.create) {
  // You don't need to understand this, but
  Object.create = function(proto) {
    // this constructor does nothing,
    function cons() {}
    // and we assign it a prototype,
    cons.prototype = proto;
    // so that the new object has the given proto without any side-effects.
    return new cons();
  };
}
// Define a new class
function dyn() {}
// with a method which returns a copy-on-write clone of the object.
dyn.prototype.cow = function() {
  // An empty object is created with this object as its prototype.  Javascript
  // will follow the prototype chain to read an attribute, but set new values
  // on the new object.
  return Object.create(this);
}
// Given an environment, read x then write to it.
function g(env) {
  console.log(env.x);
  env.x = 2;
}
// Given an environment, write x then call f with a clone.
function f(env) {
  env.x = 3;
  g(env.cow());
}
// Create a new environment.
var env = new dyn();
// env -> {__proto__: dyn.prototype}
// Set a value in it.
env.x = 1;
// env -> {x: 1}  // Still has dyn.prototype, but it's long so I'll leave it out.

f(env.cow());
// f():
//   env -> {__proto__: {x: 1}}  // Called with env = caller's env.cow()
//   > env.x = 3
//   env -> {x: 3, __proto__: {x: 1}}  // New value is set in current object
//   g():
//     env -> {__proto__: {x: 3, __proto__: {x: 1}}}  // caller's env.cow()
//     env.x -> 3  // attribute lookup follows chain of prototypes
//     > env.x = 2
//     env -> {x: 2, __proto__: {x: 3, __proto__: {x: 1}}}

console.log(env.x);
// env -> {x: 1}  // still unchanged!
// env.x -> 1


 类似资料:
  • 问题内容: 是否可以在不完全禁用JavaScript的情况下禁用AJAX? 问题答案: 如果您使用的是Firefox,则可以使用GreaseMonkey完成此操作。(https://addons.mozilla.org/en- US/firefox/addon/748 ) GM是用于将脚本应用于您访问的部分或全部页面的框架。我有禁用google- analytics下载的GM脚本(因为它们会使速度

  • 是否可以在没有实体的情况下使用JpaRepository?在这种情况下,将其替换为DTO。 如下示例所示 这种情况有替代方案吗? 注意:DTO已经映射,但我不想创建视图来将此DTO转换为实体。 我已经验证了这个主题,但没有重大进展,请使用无实体的JpaRepository交互样式 我在试这个 接口- 公共接口BffDTOInterface2{ } 我有这个错误

  • 问题内容: 如果要使用Linq-SQL,还必须将DB Table拖到设计器表面以创建实体类。 我一直喜欢我的应用程序中的完全控制权,并且不喜欢dotnet创建的类。 是否可以使用我自己的数据访问层实体类在Linq和DB之间提供此连接? 我该如何完成? 问题答案: 您可以使用Linq-to-SQL非常轻松地编写自己的类-只需使用一些属性绘制类即可。 例如,这是我的一个项目中有一个非常简单的表,它可以

  • 问题内容: 是否可以在不实现Comparable类的情况下使用Comparator?例如,如果我有以下内容: 然后可以使用comp比较两个对象吗?如果是这样,我将如何去做? 谢谢… 问题答案: 你不用。您使用。 是由对象实现的接口,用于指定它们与相同类型的其他对象的排序顺序。 是一个通用接口,只需要两个对象并告诉您它们的排序顺序。因此,您可以执行以下操作: 与: 和:

  • 问题内容: 我正在评估JOOQ是否可在仍在开发中的新系统中使用。我想避免在与应用程序一起开发数据库时生成代码,而只是为该应用程序起持久存储的作用。因此,预计数据库模式定义将由Java代码(java中的表定义)驱动。 JOOQ是否适合上述用例?是否有用于模式定义的Java DSL? 问题答案: JOOQ是否适合上述用例? 是的,许多jOOQ用户仅使用运行时库,而没有代码生成器。入门指南中提供了示例。

  • 我正在评估JOOQ在一个仍在开发中的新系统中的使用情况。当数据库与应用程序一起开发时,我希望避免代码生成,而只是在这个应用程序中扮演持久存储的角色。因此,数据库模式定义应该由Java代码(Java中的表定义)驱动。 JOOQ是否适用于上述用例?是否有用于模式定义的JavaDSL?