如何才能缓存最顶层的范围,以便稍后在原型中更深入地使用,如下所示:
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);
答案 0 :(得分:2)
由于您只有board
对象的一个实例,因此无法知道您用于访问它的内容。使用game.board
或Game.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"
答案 1 :(得分: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函数可以帮助解决这个问题)
答案 2 :(得分: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.init使this
引用游戏实例。
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();
答案 3 :(得分: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
答案 4 :(得分: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
获取同一对象的属性on
后,您必须立即授予对a
的访问权限:
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!