admin管理员组

文章数量:1323524

I'm looking through the knockout tutorials, and all the examples create the view model using the 'new' keyword:

//from learn.knockoutjs
function AppViewModel() {
  this.firstName = ko.observable("Bert");
  this.lastName = ko.observable("Bertington");
  this.fullName = koputed(function() {
    return this.firstName() + " " + this.lastName();    
  }, this);
}
ko.applyBindings(new AppViewModel());

I'm trying to avoid using the new keyword, which usually works perfectly ok, but I find trouble getting the fullName puted property to work. This is what I've e up with so far.

function makeViewModel() {
  return {
  firstName: ko.observable("Bert"),
  lastName: ko.observable("Bertington"),
  fullName: koputed(function() {
    return this.firstName() + " " + this.lastName();    
  }, this) };
}
ko.applyBindings(makeViewModel());

...which obviously fails since 'this' no longer refers to the local object inside the function passed to puted. I could get around this by creating a variable and store the view model before attaching the puted function and returning it, but if there exists a more elegant and pact solution that doesn't require me to make sure that methods that depend on each other are attached in the correct order, I'd sure like to use that instead.

Is there a better solution?

I'm looking through the knockout tutorials, and all the examples create the view model using the 'new' keyword:

//from learn.knockoutjs.
function AppViewModel() {
  this.firstName = ko.observable("Bert");
  this.lastName = ko.observable("Bertington");
  this.fullName = ko.puted(function() {
    return this.firstName() + " " + this.lastName();    
  }, this);
}
ko.applyBindings(new AppViewModel());

I'm trying to avoid using the new keyword, which usually works perfectly ok, but I find trouble getting the fullName puted property to work. This is what I've e up with so far.

function makeViewModel() {
  return {
  firstName: ko.observable("Bert"),
  lastName: ko.observable("Bertington"),
  fullName: ko.puted(function() {
    return this.firstName() + " " + this.lastName();    
  }, this) };
}
ko.applyBindings(makeViewModel());

...which obviously fails since 'this' no longer refers to the local object inside the function passed to puted. I could get around this by creating a variable and store the view model before attaching the puted function and returning it, but if there exists a more elegant and pact solution that doesn't require me to make sure that methods that depend on each other are attached in the correct order, I'd sure like to use that instead.

Is there a better solution?

Share Improve this question edited Mar 20, 2012 at 14:21 skaffman 404k96 gold badges824 silver badges775 bronze badges asked Mar 16, 2012 at 20:29 ZazZaz 3,0342 gold badges24 silver badges29 bronze badges 3
  • For me the most important question is: why are you trying to avoid the new keyword? As,John Papa said, there are ways to make objects without new but why? It is just a preference of yours (you don't like new's ) or you have some specific problems when using it ? – George Mavritsakis Commented Dec 22, 2012 at 16:09
  • I try to avoid the new keyword until I figure out this: jsperf./ffs-constructors – Zaz Commented Jan 2, 2013 at 15:26
  • @GeorgeMavritsakis: one reason to consider avoiding new is to imagine the damage that might be caused if someone using the code forgot to use new, for instance, ko.applyBindings(AppViewModel()); This will add (or replace the values of firstName, lastName, etc. on the current context, perhaps the browser's Window object. That might not be too harmful. But what if the constructor included a line such as this.Date = ...? Suddenly the Date constructor has been overridden. That's one good reason. – Scott Sauyet Commented Jan 2, 2013 at 17:04
Add a ment  | 

3 Answers 3

Reset to default 5

You can certainly get around using the new keyword by making the function self invoking, but I think you'd be better off solving the problem of the "this" keyword. I like to show people 3 ways to create viewmodels.

  1. object literal http://jsfiddle/johnpapa/u9S93/
  2. as a function http://jsfiddle/johnpapa/zBqxy/
  3. with the Revealing Module Pattern http://jsfiddle/johnpapa/uRXPn/

When using option 2 or 3 above, it is much easier to deal with the "this" keyword.

When creating it in a function, it is not necessary to return a new object. Instead you would do:

var ViewModel = function() {
    this.firstName = ko.observable("Bert");
    this.lastName = ko.observable("Bertington");
    this.fullName = ko.puted(function() {
         this.firstName() + " " + this.lastName();
    }, this);
};

Now you have access to the proper this in the puted observable.

If you really do not want to use "new" (there is no reason why you should not in this case), then you could do something like:

var createViewModel = function() { 
    var result = {
        firstName: ko.observable("Bert"),
        lastName: ko.observable("Bertington")
    };

    result.fullName = ko.puted(function() {
        return result.firstName() + " " result.lastName();
    });

    return result;
};

You can enforce new like so (taken from this great pattern resource)

function Waffle() {
    if (!(this instanceof Waffle)) {
    return new Waffle();
    }

    this.tastes = "yummy";
}

However I am unsure what you mean by

I'm trying to avoid using the new keyword, which usually works perfectly ok, but I find trouble getting the fullName puted property to work. This is what I've e up with so far.

This should work fine, can you show us a concrete example in jsfiddle that doesn't work with using new.

Hope this helps.

本文标签: knockoutjsMaking a javascript knockout viewmodel without the new keywordStack Overflow