模块模式和这个

Module pattern and this

本文关键字:模式 模块      更新时间:2023-09-26

我正在为我的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