Access to a private (local) variable inside the closure area

I am doing a chrome google extension and am trying to get a link to a local variable within the close 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 script content is to inject the function into the Match prototype just to get the player_red and player_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 not defined under this .

I found this question through a search. The solution is to "wrap the constructor in a new constructor, and then set the prototypes equal . " Unfortunately, this does not work for me, since I do not have access to the source script of the website, and probably because:

  • even when creating a new myMatch , the new myMatch does not inherit the player_red and player_blue from its original Match instance.
  • Are there any workarounds? Thanks.
+4
source share
1 answer

Partial Solution Notes:

Please note that the code snippets below show only "some alternatives that may or may not provide sufficient access." This is due to the fact that they do not fix the values ​​(objects-objects) inside the constructor, but only transfer the values ​​inside.

A “complete solution” can also wrap the Player constructor and use a property or other mechanism to “remember” objects created for different input values; Alternatively, he could remember the order in which the object was created. This could then be used to transfer the Match and then retrieve the created Players from the shared repository after starting the Match constructor, however, this data remains as an exercise. The player wrap code may use the code below (assuming Player is a global / available property).


An exact query is not possible given the above context.

Variables (real variables, not properties) can only be accessed from the area in which they are declared, or from the nested area, because they are allowed using visibility chains. This also includes the use of eval . Although this may seem like a limitation, it also ensures that area chains (and their variables) cannot be deleted externally if they are not open.

However, consider this fun approach that takes advantage of the fact that an explicit object can be return ed from the constructor:

 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 .

Happy coding.


Update:

Below is the modification above to work with "completing the constructor in the new constructor, and then set the prototypes to equal," as described in the link in the message. The trick is to "steal" a global property name. I also changed the code to keep oldMatch "private" to avoid pollution.

 // 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 can still break depending on the specific assumptions made in the methods of the Match object.


An example of how to invert ("extract") data from the Player constructor:

 // 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 
+2
source

All Articles