var Model = function(client, collection) {
  this.client = client;
  this.collection = collection;
};

Model.prototype = {
  constructor: Model,
  getClient: function(callback) {
    this.client.open(callback);
  },
  getCollection: function(callback) {
    var self = this;

    this.getClient(function(error, client) {
      client.collection(self.collection, callback);
    });
  },
  extend: function(key, fn) {
    var self = this;

    this[key] = function() {
      fn.call(self); // A
    };
  }
};

Was ich erreichen möchte, ist, dass ich die Funktionalität des Modells "erweitern" kann.

var userModel = new Model(client, 'users');
userModel.extend('create', function(data, callback) {
  this.getCollection(function(error, collection) {
    collection.insert(data, { safe: true }, function(error, doc) {
      callback.call(doc);
    });
  });
});

userModel.create({ fullName: 'Thomas Anderson' }, function() {
  console.log(this); // { _id: '123456789012345678901234', fullName: 'Thomas Anderson' }
});

Irgendwann bei A muss ich Parameter übergeben, die Parameteranzahl der benutzerdefinierten Funktion "create" (Daten und Rückruf) ist variabel.

Ist das möglich und wenn ja wie?

1
onlineracoon 9 Okt. 2012 im 00:42

4 Antworten

Beste Antwort

Ja! Sie möchten die Methode .apply gegenüber der Methode .call verwenden. Beide wenden den Kontext an, aber die Methode .apply verwendet ein Array für Argumente - oder eine Argumentensammlung selbst!

extend: function(key, fn) {
    var self = this;

    this[key] = function() {
      fn.apply(self,arguments); // the special arguments variable is array-like
    };
  }
3
zetlen 8 Okt. 2012 im 20:47
 this[key] = function() {
      fn.apply(self, arguments);
    };
0
Artur Udod 8 Okt. 2012 im 20:48

Sofern Sie keine versteckten Gründe für das Erstellen einer extend -Methode im Prototyp und das Erzwingen eines Bereichs haben, können Sie die Methode stattdessen einfach der erstellten Instanz zuweisen:

var userModel = new Model(client, 'users');
userModel.create = function(data, callback) {
  this.getCollection(function(error, collection) {
    collection.insert(data, { safe: true }, function(error, doc) {
      callback.call(doc);
    });
  });
});

Es wird schneller, sauberer und Sie müssen sich keine Gedanken darüber machen, Argumente über eine andere Funktion zu übergeben.

Das Durchsetzen eines Bereichs (oder Kontexts) durch Einkapseln ist nicht immer gut, da Sie die Dynamik der Sprache einschränken.

0
David Hellsing 8 Okt. 2012 im 21:08

Nur noch eine Sache nach dem @ zetlen-Kommentar: Der Bereich (dies) einer Funktion steht hinter dem letzten Punkt des Funktionsaufrufs, in diesem Fall:

userModel.create();

Die Variable "this" der Funktion lautet "userModel".

Solange Sie es mit "modelname.functionName ()" aufrufen, müssen Sie sich nicht selbst übergeben:

extend: function(key, f) {
    this[key] = f;
}

(oder nur)

userModel.someMethod = function() { ... };

Wenn Sie dann modelkey aufrufen, übergeben Sie die Argumente direkt an die Funktion und haben den gewünschten Bereich.

var userModel = new Model(...);
userModel.extend('hi', function(arg) {
  this === userModel;
  arg === 42;
});
userModel.hi(42);

Schauen Sie sich diese Geige an, um sie zu sehen: http://jsfiddle.net/NcLQB/1/

Aber bitte denken Sie daran, als wenn Sie die Funktion des Modells herausnehmen, wird es nicht mehr den Umfang haben. Wenn Sie dies tun, tun Sie es besser wie Ihr Snippet.

var funct = userModel.hi;
funct(); // this === global!!!

// OR

// When the event is fired the scope isn't userModel
otherThing.on('someEvent', userModel.hi);
0
A. Matías Quezada 8 Okt. 2012 im 21:02