简体   繁体   English

访问闭包范围内的私有(局部)变量

[英]Access private (local) variable inside a closure scope

I'm making a google chrome extension and trying to get reference of a local variable within a closure scope. 我正在做一个谷歌浏览器扩展程序,并试图获取闭包范围内的局部变量的引用。

// The script model of the target website
// I can't change any code of these
function Player(playerName){
    this.name = playerName;
    this.score = 0;
}

function Match(playerRed,playerBlue){
    var player_red = new Player(playerRed);
    var player_blue = new Player(playerBlue);
}

var tennis = new Match("Mike","John")

so what I'm trying to do in my content script is to inject a function into prototype of Match just to get the variable player_red and player_blue : 所以我要在内容脚本中执行的操作是将一个函数注入Match原型中,以获取变量player_redplayer_blue

function Match(playerRed,playerBlue){
    var player_red = new Player(playerRed);
    var player_blue = new Player(playerBlue);

    //hoping to add this into Match.prototype
    this.showMatchInfo = function(){
            alert(player_red.name + " vs " + player_blue.name);
    }
}

but this will not work because player_red and player_blue isn't defined under this . 但这不起作用,因为未在this下定义player_redplayer_blue

I found this question through search. 我通过搜索发现了这个问题 The solution is to "wrap the constructor in a new constructor and then set the prototypes equal" . 解决方案是“将构造函数包装在新的构造函数中,然后将原型设置为相等” Unfortunately this doesn't work for me as I have no access to the original script of the website and probably because: 不幸的是,这对我不起作用,因为我无法访问网站的原始脚本,并且可能是因为:

  • even by create new myMatch , the new myMatch doesn't not inherit the player_red and player_blue variable from their original Match instance. 即使通过创建新的myMatch ,新的myMatch也不会从其原始Match实例中继承player_redplayer_blue变量。
  • Are there any possible workarounds? 有没有可能的解决方法? Thanks. 谢谢。

Notes on "partial solution": 关于“部分解决方案”的注释:

Please note that the code snippets posted below only show "some alternatives which may or may not provide enough to get by". 请注意,下面发布的代码段仅显示“可能无法提供足够的替代方法”。 This is because they don't capture the values (Player objects) within the constructor, but only wrap the values going inside. 这是因为它们没有捕获构造函数中的值(Player对象),而是仅将值包装在内部。

A "full solution" might also wrap the Player constructor and use a property or other mechanism to "remember" the objects created for different input values; “完整解决方案”还可以包装Player构造函数,并使用属性或其他机制来“记住”为不同输入值创建的对象。 alternatively, it could remember object creation order . 或者,它可以记住对象创建顺序 This could then be used to wrap Match and then extract the created Players from the shared store after the Match constructor had run -- those details, however, are left as an exercise. 然后,可以将其用于包装Match,然后在Match构造函数运行之后从共享存储中提取创建的Players;但是,这些细节留作练习。 The Player wrapping code can utilize the code presented below (assuming Player is a global/accessible property). Player包装代码可以利用下面提供的代码(假设Player是一个全局/可访问的属性)。


The exact request is not possible given the above context. 在上述情况下,确切的请求是不可能的。

Variables (real variables, not properties) can only be accessed from the scope they are declared in or a nested scope as they are resolved through scope chains. 变量(实变量,不是属性)只能通过在范围链中解析的声明范围或嵌套范围访问。 This also includes usage of eval . 这也包括使用eval While this may seem like a limitation, it also ensures that scope chains (and their variables) can't be externally mucked with unless exposed. 尽管这似乎是一个限制,但它还确保除非公开,否则范围链(及其变量)不会在外部被破坏。

However, consider this fun approach, which utilizes the fact that an explicit object can be return ed from a Constructor: 但是,请考虑这种有趣的方法,该方法利用了可以从构造方法return显式对象的事实:

var oldMatch = Match
// note this form, else above would be pre-clobbered
Match = function Match (playerRed, playerBlue) {
    var m = new oldMatch(playerRed, playerBlue)
    // either "inject" method here, or save in object for later
    m.myPlayerRed = playerRed
    m.myPlayerBlue = playerBlue
    return m
}

Of course, this will break things like new Match(...) instanceof Match . 当然,这会破坏诸如new Match(...) instanceof Match类的东西。

Happy coding. 快乐的编码。


Update: 更新:

Here is a modification of the above to work with the "wrap the constructor in a new constructor and then set the prototypes equal" method as discussed in the link in the post. 这是对上述内容的修改,可以使用“将构造函数包装在新的构造函数中,然后将原型设置为相等”的方法,如本文链接中所述。 The trick is "stealing" the global properties name. 诀窍是“窃取”全局属性名称。 I have also altered the code to keep oldMatch "private" to avoid pollution. 我还更改了代码,以使oldMatch保持“私有”状态以避免污染。

// note this form, else Match property would be pre-clobbered
Match = (function (oldMatch) {
    function Match (playerRed, playerBlue) {
        oldMatch.call(this, playerRed, playerBlue);
        // either "inject" method here, or save in object for later
        this.myPlayerRed = playerRed
        this.myPlayerBlue = playerBlue
    }
    Match.prototype = oldMatch.prototype
    return Match
})(Match)

Unlike the first code snippet, this should work with new Match(...) instanceof Match , but it may still break depending upon particular assumptions made within the Match object methods. 与第一个代码段不同,此代码应与new Match(...) instanceof Match ,但仍可能会中断,具体取决于Match对象方法中的特定假设。


Example of how to invert ("extract") data from Player constructor: 如何从Player构造函数反转(“提取”)数据的示例:

// original -- remember this method will only work
// if Player is used as a property (and not itself a closure'd variable)
function Player (name) {
    this.name = name
}

Player = (function (oldPlayer) {
    function Player (name) {
        oldPlayer.call(this, name)
        var fn = arguments.callee
        fn.recent = fn.recent || []
        fn.recent.push([name, this])         
    }
    Player.prototype = oldPlayer.prototype
    return Player
})(Player)

var p1 = new Player("fred");
var p2 = new Player("barney");

alert("instanceof check? " + p1 instanceof Player)
alert("name check? " + ("barney" == p2.name))

alert(Player.recent.join(","))
Player.recent = [] // reset

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM