6

如何缓存最顶层的范围,以便以后在原型中更深入地使用,如下所示:

var Game = function(id){
   this.id = id;
};

Game.prototype = {
  board : {
    init: function(){
       // obviously "this" isn't the instance itself, but will be "board"
       console.log(this.id);
    }
  }
}

var game = new Game('123');
game.board.init(); // should output "123"

更新:

好吧,现在我考虑一下,我可以使用apply/call并传递上下文......

game.board.init.apply(game);
4

5 回答 5

2

由于您只有一个board对象实例,因此它无法知道您使用什么来访问它。使用game.boardGame.prototype.board访问该对象给出完全相同的结果。

如果您不想board为每个Game实例创建一个对象,则必须告诉对象在每次调用时它应该认为自己属于board哪个对象:Game

game.board.doSomething(game);

或者:

Game.prototype.board.doSomething(game);

编辑:

要为每个Game实例创建一个板,请为 构造一个构造函数Board,并使板对象知道Game它所属的实例:

function Game(id) {
  this.id = id;
  this.board = new Board(this);
}

Game.prototype = {
};

function Board(game) {
  this.game = game;
}

Board.prototype = {
  init: function(){
    console.log(this.game.id);
  }
};

var game = new Game('123');
game.board.init(); // outputs "123"
于 2013-05-11T23:26:08.980 回答
1

没有“深入原型”之类的东西。"this" 将始终是您调用它的对象,除非通过回调或各种重新绑定方式改变了它。如果您拆分概念并将它们链接在一起,您的理智损失会更少:

Board = function (game) {
    this.game = game;
}

Board.prototype.init = function () {
    console.log(this.game.id);
}

Game = function () {
    this.id = 123;
    this.board = new Board(game);
}

Game.prototype = {};

或者,如果你一心想让它们都使用相同的基础,你可以做一些疯狂的黑客攻击,比如......

Game = function () {
    this.id = 123;
    var self = this;
    for(var p in this.board) {
        var property = this.board[p];
        if(typeof property == 'function') {
            this.board[p] = function (method) {
                return function () {
                    method.apply(self, arguments);
                }
            }(property)
        }
    }
}

这是一个彻头彻尾的黑客攻击,它会让你的同事讨厌你。(如果您使用的是下划线库,则有一个 bindAll 函数可以帮助您解决这些问题)

于 2013-05-11T23:08:01.550 回答
0

更新

如果您不想为每个函数提供范围,则必须为每个游戏创建一个新实例。如果需要,您可以通过在构造函数Game中将板构造函数设为变量来将板私有化Game

var Game = function(id){
    //Keep board private to Game
    var boardClass = function (scope) {
        this.scope = scope;
        this.init = function () {
            if ( this.scope instanceof Game ) {
                console.log(this.scope.id);
            }
        };
    };
    this.id = id;
    //Instantiate a new board for each game
    this.board = new boardClass(this);
};

var game = new Game(123);
//Logs 123
game.board.init();

var game2 = new Game(456);
//Logs 456
game2.board.init()

//Still Logs 123
game.board.init();

不要使用下面的代码,因为正如Guffy指出的那样,一个棋盘对象在所有 Game 实例之间共享。因此,以下解决方案不适用于多个游戏。


您可以强制 game.board.initthis引用游戏实例。

var Game = function(id){
    this.id = id;
    this.board.game = this;
};

Game.prototype = {
    board : {
        game: {},
        init: function() {
            //check if this is an instance of board by seeing if it has a game property
            if(this.game) {
                //make this refer to the game if it is referring to the board
                this.init.apply(this.game);
            }
            console.log(this.id);
        }
    }
}

var game = new Game(123);
//Logs 123
game.board.init();

var game2 = new Game(456);
//Logs 456
game2.board.init();

//Logs 456...oops!
game.board.init();

或者您可以简单地将游戏实例设置为板上的属性。

var Game = function(id){
    this.id = id;
    this.board.scope = this;
};

Game.prototype = {
    board : {
        init: function(){
           // can check if the scope is what we want it to be
           if( this.scope instanceof Game )
                console.log(this.scope.id);
        }
    }
}

var game = new Game(123);
//Logs 123
game.board.init();

var game2 = new Game(456);
//Logs 456
game2.board.init();

//Logs 456...oops!
game.board.init();
于 2013-05-12T01:14:14.093 回答
0

这样做是一个非常糟糕的主意,因为它在某些情况下会导致非常奇怪的行为,但有可能:

var Model = function(x) { this.x = x };

Object.defineProperty(Model.prototype, 'a', (function() {
  var lastSelf;
  function get() { return lastSelf.x }
  get.on = function () { return lastSelf.x * 2 };
  return { get() { lastSelf=this; return get } };
})());

var m = new Model(17);
console.log(m.a(), m.a.on());

为什么?我在下面看到您的答案,试图了解什么是不好的情况。

你不能通过a变量。您必须在获得同一对象的属性后立即
授予访问权限:ona

var m1 = new Model(1), m2 = new Model(3);
console.log(m1.a(), m2.a(), m1.a.on(), m2.a.on()); // 1 3 2 6 - ok
var a1 = m1.a, a2 = m2.a;
console.log(m1.a(), m2.a(), a1.on(), a2.on()); // 1 3 6 6 - ooops!
console.log(m1.a(), m2.a(), m1.a(), a1.on(), a2.on()); // 1 3 1 2 2 - ooops!
于 2016-03-16T09:46:12.803 回答
0

试试这个方法

var Model = function() {this.b = 2;};
Model.prototype.a = function() {
   console.log(this); 
   var that = this;
   this.a.on = function(){
     console.log(that); console.log(m.b);
   };
}

var m = new Model();
m.a();
m.a.on();

你需要做两件事

  • 在原型方法内部创建设置方法,意味着on应该在内部定义,a以便它可以访问this.

  • 在其中创建父引用的副本that并在其中使用它on

于 2016-03-16T09:35:16.130 回答