模块模式和这个
Module pattern and this
我正在为我的JavaScript"类"使用模块模式。声明我返回的类的var self
outisde,然后在类构造函数中将其设置为this
,这样我就不必担心上下文切换了。在这个小例子中,这可能是不必要的,这只是一个例子。
示例:
var Seat = (function() {
var self = null;
function Seat(startX, startY, inputSeatNumber, inputTableNumber) {
self = this;
self.radius = 10;
self.x = startX; self.y = startY;
self.seatNumber = inputSeatNumber;
self.tableNumber = inputTableNumber;
}
Seat.prototype.moveTo = function(newX, newY) {
if(newX >= 0 && newY >= 0) {
self.x = newX; self.y = newY;
}
};
return Seat;
})();
EDIT:添加的示例
var SeatingChartView = (function() {
function SeatingChartView(canvas_id, seatingChartController, seatForm) {
this.stage = new createjs.Stage(canvas_id);
this.controller = seatingChartController;
this.seatForm = seatForm;
this.disableRightClick(canvas_id);
}
SeatingChartView.prototype.render = function() {
this.stage.update();
}
SeatingChartView.prototype.addSeat = function(newSeat) {
var newCircle = new createjs.Shape();
newCircle.graphics.beginFill("black").drawCircle(0, 0, 10);
newCircle.x = newSeat.x;
newCircle.y = newSeat.y;
newCircle.seat = newSeat;
newCircle.on('click', function(event) {
if(event.nativeEvent.button == 2) {
this.seatForm.open(event.currentTarget.seat);
}
});
newCircle.on('pressmove', this.controller.moveSeat)
this.stage.addChild(newCircle);
}
SeatingChartView.prototype.removeSeat = function(seat) {
this.stage.children.forEach(function(child) {
if(child.seat === seat) {
this.stage.removeChild(child);
}
});
}
SeatingChartView.prototype.setBackground = function(imageLocation) {
this.background = new createjs.Bitmap(imageLocation);
window.setTimeout(function() {
this.stage.canvas.width = this.background.image.width;
this.stage.canvas.height = this.background.image.height;
this.stage.addChild(this.background);
this.stage.update();
}.bind(this), 500);
}
SeatingChartView.prototype.disableRightClick = function(canvas_id) {
$(function() {
$('#' + canvas_id).bind('contextmenu', function(e) {
return false;
});
});
}
return SeatingChartView;
})();
在这种情况下,Seat
的每个新实例都将共享最新的Self
对象,因为它是在构造函数中设置的。你应该避免这样做。
一个更实用的演示示例可能是这样的,您需要确保this
是该类的实例。
function Foo() {
var _this = this;
_this.someItem = {};
_this.go = function() {
doSomethingElse(function(result) {
_this.someItem.something = result; // _this and this are different
});
};
};
function doSomethingElse(callback) {
callback('asdf');
}
var foo = new Foo();
foo.go();
对于使用该模式的示例,如果有任何好处,您可以在每个方法中定义_this
(这个示例不会,但更复杂的示例可能会):
Seat.prototype.moveTo = function(newX, newY) {
var _this = this;
if(newX >= 0 && newY >= 0) {
_this.x = newX; _this.y = newY;
}
};
是的,通过这种方式,Seat
的所有实例都将具有相同的this
,从而导致各地出现问题。只需移除var self
,并在所有使用self
的地方使用this
。在您给出的代码中,不会丢失对this
的引用。
(@添加示例)现在你的问题更有意义了。
与其尝试同时处理所有方法,不如在使用具有不同this
的函数(任何不在原型或实例上的函数)的每个点上处理它。
如果回调中不需要this
,我只需要使用.bind
使实例this
在回调中可用。然而,请注意,.bind
在一些(非常)旧的IE版本中不受支持,因此您需要一个polyfil来为这些版本工作,或者将this
存储在var.中
SeatingChartView.prototype.addSeat = function(newSeat) {
var newCircle = new createjs.Shape();
newCircle.graphics.beginFill("black").drawCircle(0, 0, 10);
newCircle.x = newSeat.x;
newCircle.y = newSeat.y;
newCircle.seat = newSeat;
newCircle.on('click', function(event) {
if(event.nativeEvent.button == 2) {
this.seatForm.open(event.currentTarget.seat);
}
}.bind(this)); // modified here, added `.bind(this)`
newCircle.on('pressmove', this.controller.moveSeat)
this.stage.addChild(newCircle);
}
这将完全否定"分类"的目的。但在JS中,它被称为原型。
原则上,您希望在创建新实例时"复制"基本原型。基础原型在扩展时应避免更改。
假设您已经完成了所做的操作,那么Seat
的所有实例都将具有相同的属性。最糟糕的是,在创建Seat
的新"副本"时,所有其他先前创建的副本的值都将发生更改。
由于您希望this
保持对Seat
的引用,我建议使用以下模式:
var Base = {
init: function(arg) {
this.name = arg;
},
getName: function() {
return this.name;
}
}
Base.init('foo');
Base.getName(); // returns 'foo'
您的转换代码:
var Seat = {
init: function(startX, startY, inputSeatNumber, inputTableNumber) {
this.radius = 10;
this.x = startX;
this.y = startY;
this.seatNumber = inputSeatNumber;
this.tableNumber = inputTableNumber;
},
moveTo: function(newX, newY) {
if (newX >= 0 && newY >= 0) {
this.x = newX; this.y = newY;
}
},
setBackground: function(imageLocation) {
var self = this;
this.background = new createjs.Bitmap(imageLocation);
setTimeout(function() {
self.stage.canvas.width = self.background.image.width;
self.stage.canvas.height = self.background.image.height;
self.stage.addChild(self.background);
self.stage.update();
}, 500);
}
}
扩展原型:
var vipSeat = Object.create(Seat);
vipSeat.init( //your init values )
您也可以不创建init方法,只需使用Object.create的第二个参数为原型分配初始值:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Example:_Using_propertiesObject_argument_with_Object.create
- Javascript,访问一个主要对象模块模式中的每个对象
- 模块模式和这个
- 显示模块模式在Knockout中设置模型的新实例
- Javascript中的模块模式和揭示模块模式是否仅在创建API时有用;s
- 用于多个选项卡和模块化的knockoutjs设计模式
- JavaScript模块模式-如何在使用对象/函数之前激发构造函数/init函数
- TypeScript代码类似于揭示模块模式结构
- 为什么在javascript中的模块模式中实现Lazy函数时范围会发生变化
- JavaScript:模块模式差异
- 显示模块模式中的私有成员
- 如何将window.setTimeout与javascript和模块模式一起使用
- j查询模块模式未命名 |如何访问“$”
- 挖空和显示模块模式的数据绑定问题
- 传递参数时如何避免模块模式中的 getter/setter 函数
- 将变量传递给 Javascript 模块化模式方法
- JavaScript 模块模式给出了意想不到的结果
- 从模块模式开始
- 试图通过模块模式在DOM元素上实现change()事件
- 揭示模块模式、KnockoutJS和CoffeeScript
- JavaScript 设计模式:模块模式和揭示模块模式之间的区别