Pregunta

Estoy creando una extensión de Google Chrome e intentando obtener una referencia de una variable local dentro de un alcance de cierre.

// 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")

Entonces, lo que estoy tratando de hacer en mi script de contenido es inyectar una función en el prototipo de Matchsolo para obtener la variable player_red y 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);
    }
}

pero esto no funcionará porque player_red y player_blue no está definido en this.

encontré esto pregunta a través de la búsqueda.La solución es "envuelva el constructor en un nuevo constructor y luego iguale los prototipos".Lamentablemente, esto no funciona para mí porque no tengo acceso al script original del sitio web y probablemente porque:

  • incluso creando nuevos myMatch, el nuevo myMatch no no hereda el player_red y player_blue variable de su original Match instancia.
  • ¿Existen posibles soluciones?Gracias.
¿Fue útil?

Solución

Notas sobre la "solución parcial":

Tenga en cuenta que los fragmentos de código publicados a continuación solo muestran "algunas alternativas que pueden proporcionar o no lo suficiente para salir adelante".Esto se debe a que no capturan los valores (objetos Player) dentro del constructor, sino que solo envuelven los valores que van dentro.

Una "solución completa" también podría incluir el constructor Player y utilizar una propiedad u otro mecanismo para "recordar" los objetos creados para diferentes valores de entrada;alternativamente, podría recordar el orden de creación de los objetos..Esto luego podría usarse para envolver Match y luego extracto los jugadores creados desde la tienda compartida después de que se haya ejecutado el constructor del partido; sin embargo, esos detalles se dejan como ejercicio.El código de ajuste del Reproductor puede utilizar el código que se presenta a continuación (asumiendo que el Reproductor es una propiedad global/accesible).


La solicitud exacta no es posible dado el contexto anterior.

Solo se puede acceder a las variables (variables reales, no propiedades) desde el alcance en el que están declaradas o desde un alcance anidado, ya que se resuelven a través de cadenas de alcance.Esto también incluye el uso de eval.Si bien esto puede parecer una limitación, también garantiza que las cadenas de alcance (y sus variables) no puedan ser manipuladas externamente a menos que se expongan.

Sin embargo, considere este enfoque divertido, que utiliza el hecho de que un objeto explícito puede ser returned de un 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
}

Por supuesto, esto romperá cosas como new Match(...) instanceof Match.

Feliz codificación.


Actualizar:

Aquí hay una modificación de lo anterior para trabajar con el método "envolver el constructor en un nuevo constructor y luego establecer los prototipos iguales" como se explica en el enlace de la publicación.El truco consiste en "robar" el nombre de las propiedades globales.También he modificado el código para mantener oldMatch "privado" para evitar la contaminación.

// 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)

A diferencia del primer fragmento de código, esto debería funcionar con new Match(...) instanceof Match, pero aún así puede fallar dependiendo de suposiciones particulares hechas dentro de los métodos del objeto Match.


Ejemplo de cómo invertir ("extraer") datos del 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
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top