【问题标题】:How do I create a model of a function?如何创建函数模型?
【发布时间】:2013-12-11 23:38:27
【问题描述】:

我想创建一个类的模型,比如说

var car = function(){
  var color;
  this.setColor = function(clr){
    color = clr;
  }
}

现在我想要更多的课程,例如volvo()。但我也希望car() 拥有的所有东西都可以在volvo() 中使用,就像这样

var volvo = function(){
  ...probably some code here
  this.getColor = function(){
    return color;
  }
}

我该怎么做?

【问题讨论】:

  • 你的意思是伪经典的类-实例关系吗?
  • 除非您有某种面向公众的方法或属性允许访问相关颜色,否则不会。
  • 您可以使用 Resig 辅助函数,但最好了解构造函数和原型在 JavaScript 中的工作原理。也许这个答案可以帮助:stackoverflow.com/a/16063711/1641941

标签: javascript class model inheritance


【解决方案1】:

您要实现的目标称为继承,由于 JavaScript 不像 Java、C# 和其他语言那样基于类,而且它是基于原型的,因此实现起来并不容易。

有很多方法可以实现:

一种方法是使用诸如Backbone.jsAngularJSEmber.js 之类的框架。然后在您的模型类中,基本上您可以使用Extend 关键字,然后开箱即用地获得继承。

另一种方法是将以下由 John Resig(jQuery 的创建者)编写的代码包含到您的应用程序中:

    /* Simple JavaScript Inheritance
     * By John Resig http://ejohn.org/
     * MIT Licensed.
     */
     // Inspired by base2 and Prototype
    (function(){
  var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;

  // The base Class implementation (does nothing)
  this.Class = function(){};

  // Create a new Class that inherits from this class
  Class.extend = function(prop) {
    var _super = this.prototype;

    // Instantiate a base class (but only create the instance,
    // don't run the init constructor)
    initializing = true;
    var prototype = new this();
    initializing = false;

    // Copy the properties over onto the new prototype
    for (var name in prop) {
      // Check if we're overwriting an existing function
      prototype[name] = typeof prop[name] == "function" &&
        typeof _super[name] == "function" && fnTest.test(prop[name]) ?
        (function(name, fn){
          return function() {
            var tmp = this._super;

            // Add a new ._super() method that is the same method
            // but on the super-class
            this._super = _super[name];

            // The method only need to be bound temporarily, so we
            // remove it when we're done executing
            var ret = fn.apply(this, arguments);
            this._super = tmp;

            return ret;
          };
        })(name, prop[name]) :
        prop[name];
    }

    // The dummy class constructor
    function Class() {
      // All construction is actually done in the init method
      if ( !initializing && this.init )
        this.init.apply(this, arguments);
    }

    // Populate our constructed prototype object
    Class.prototype = prototype;

    // Enforce the constructor to be what we expect
    Class.prototype.constructor = Class;

    // And make this class extendable
    Class.extend = arguments.callee;

    return Class;
  };
})();

加载此代码后,您将能够使用它来解决您的问题:

var Car = Class.Extend({
  setColor: function(clr){
    color = clr;
  }
});

var volvo = Car.Extend({
   getColor: function () {
      return color;
   }
});

JavaScript Inheritance by John Resig 帖子中了解它。祝你好运!

【讨论】:

    【解决方案2】:

    您可以在没有任何额外库的情况下做到这一点 - 只是有点冗长。

    jsFiddle

    首先建立一个car类并给它一些方法(setColorsetMakesetModel):

    function car(make,model){
        console.log( 'car constructor' );
        this.setMake( make );
        this.setModel( model );
    }
    car.prototype.setColor = function(color){ this.color = color; };
    car.prototype.setMake  = function(make ){ this.make  = make;  };
    car.prototype.setModel = function(model){ this.model = model; };
    car.prototype.toString = function(){ return 'This is a ' + this.color + ' ' + this.make + ' ' + this.model + ' car' };
    

    那么你可以从汽车继承:

    function volvo( model ){
        console.log( 'volvo constructor' );
        car.call( this, 'volvo', model );
    }
    volvo.prototype = Object.create( car.prototype );
    volvo.prototype.constructor = volvo;
    

    然后查看各个部分:

    • function volvo( model ){} 定义了一个 volvo 类。
      • 并且在构造函数中car.call( this, 'volvo', model ); 用于调用固定make 为volvo 的父类的构造函数。
    • volvo.prototype = Object.create( car.prototype );volvo 类设置为从car 类继承。
    • volvo.prototype.constructor = volvo; 用于确保volvo 类使用volvo 构造函数(如果没有这行,前面的语句将导致它使用car 构造函数)。

    然后我们可以测试一下:

    var c = new car('Ford', 'Fiesta');
    c.setColor('Red');
    console.log( c.toString() );
    
    var v = new volvo( 'S10' );
    v.setColor( 'Grey' );
    console.log( v.toString() );
    

    输出是(包括显示何时调用构造函数的日志条目):

    car constructor
    This is a Red Ford Fiesta car
    volvo constructor
    car constructor
    This is a Grey volvo S10 car
    

    如果您需要为 Object.create 使用 polyfill,那么您可以使用:

    if (!Object.create) {
      Object.create = (function(){
        function F(){}
    
        return function(o){
          if (arguments.length != 1) {
              throw new Error('Object.create implementation only accepts one parameter.');
          }
          F.prototype = o
            return new F()
        }
      })()
    }
    

    【讨论】:

    • 请不要通过创建新的 Parent 实例来继承原型部分,如果您需要对旧浏览器的支持,请改用 Object.create 并填充它。
    • 如果您的继承深度达到 3 级,那么如果在 this 是 GrandChild 且 this.__super__ 将引用 Child(不是父级)。您将有一个永无止境的 Child 构造函数循环调用自身。而是使用 Child.parent=Parent.prototype; 并在构造函数中执行:Child.parent.constructor.call(this,args);
    【解决方案3】:
    function Car(color) {
        this.getColor = function() {
            return color;   
        };
    
        this.extend = function() {
            function F() {};
            F.prototype = this;
            return new F();
        };
    }
    
    car = new Car("black");
    console.log(car.getColor());
    
    vw = car.extend();
    vw.slogan = function() { return "Das Auto"; };
    
    console.log(vw.getColor());
    console.log(vw.slogan());
    
    gulf = vw.extend();
    gulf.isHatchBack = function() { return true; };
    
    console.log(gulf.getColor());
    console.log(gulf.slogan());
    console.log(gulf.isHatchBack());
    

    【讨论】:

    • 有趣的方法,我将如何制作 10 个 VW 实例?
    • 由于 Car.extend 返回的是实例而不是构造函数,因此您不能这样做 myOldBeetle=new VW(1972); 其中 1972 年是它的构建年份。再说一遍,您将如何创建一堆 VW 实例
    • 人们总是试图让 JS 像 java 一样工作,对我来说这不是 JS 的重点。拥抱 it 原型系统,不要认为“是一个”认为“过去是一个,现在是别的东西”这是对 JavaScript 的致敬,你可以让它像 Java、c++ 或 C# 这样的 sudo 经典语言工作。事实上,C# 已经多次复制了它。
    • 你不必把婴儿和洗澡水一起扔出去。构造函数初始化是一件非常有用的事情。对象需要在创建实例时的某个时间点进行初始化,这意味着设置特定于实例的成员。
    • 很公平,在这种情况下,extend 应该称为 copy。
    【解决方案4】:

    您可能会觉得这也很有趣:http://jsbin.com/IgOCAvI/1/edit

    function Car() {
      this.carData = {};
    }
    
    Car.prototype = {
    
      set: function(ob) {
        var obType = Object.prototype.toString.call(ob);
        if( ob && obType.match('Obj') ){
          for (var key in ob) {
            if ( ob.hasOwnProperty(key) ){
              this.carData[key] = ob[key];
              // console.log("Stored: "+ key +':'+ ob[key] ); // TEST
            }
          }
        }else{
          // alert(ob +' ('+obType+')\n is not an Object!');
        } 
      }, 
    
      get: function(key) {
        if(typeof key == "string"){
          var arr = key.replace(/ /g, "").split(',');
          for(var i=0; i<arr.length; i++){ arr[i] = this.carData[arr[i]]; }
          // console.log( arr ); // TEST
          return arr;
        }else{ // Return the whole Object!
          // console.log( JSON.stringify(this.carData, null, 2) ); // TEST
          return this.carData;
        }
      }
    
    };
    

    用法:

    // Create new instance of Car 
    var car1 = new Car();
    
    // Populate with values
    car1.set({manufacturer:"Volvo", model:"S40", color:"green", doors:5, damage:"front fender"});
    // Get Array collection
    console.log(  car1.get("color")  );                    // [Green]
    console.log(  car1.get("color, doors, firstOwner")  ); // [Green, 5, undefined]
    // Get whole Object
    console.log(  car1.get()  );                           // [object Object]
    // Get specific value from Object
    console.log(  car1.get().color  );                     // "Green"
    // Let's change a key value
    car1.set({color:"red"});
    // Test 
    console.log(  car1.get()  );  
    
    
    //  CAR2
    var car2 = new Car();
    // let's see if the car2 inherited some property of car1
    console.log( car2.get('color') );  // [undefined] // nope.
    car2.set({manufacturer:"Nissan", model:"Micra", color:"gray", doors:3, damage:"none"});
    // ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-04
      • 1970-01-01
      • 2019-08-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多