代码之家  ›  专栏  ›  技术社区  ›  Ali

javascript对象中的构造函数

  •  398
  • Ali  · 技术社区  · 15 年前

    javascript类/对象是否可以有构造函数?它们是如何创建的?

    19 回复  |  直到 7 年前
        1
  •  404
  •   Christophe Roussy    9 年前

    使用原型:

    function Box(color) // Constructor
    {
        this.color = color;
    }
    
    Box.prototype.getColor = function()
    {
        return this.color;
    };
    

    隐藏“color”(有点像私有成员变量):

    function Box(col)
    {
       var color = col;
    
       this.getColor = function()
       {
           return color;
       };
    }
    

    用途:

    var blueBox = new Box("blue");
    alert(blueBox.getColor()); // will alert blue
    
    var greenBox = new Box("green");
    alert(greenBox.getColor()); // will alert green
    
        2
  •  248
  •   Blixt    12 年前

    这是一个我在javascript中用于OOP类似行为的模板。如您所见,您可以使用闭包模拟私有(静态和实例)成员。什么 new MyClass() will-return是一个对象,只分配给 this 对象和中的 prototype “类”的对象。

    var MyClass = (function () {
        // private static
        var nextId = 1;
    
        // constructor
        var cls = function () {
            // private
            var id = nextId++;
            var name = 'Unknown';
    
            // public (this instance only)
            this.get_id = function () { return id; };
    
            this.get_name = function () { return name; };
            this.set_name = function (value) {
                if (typeof value != 'string')
                    throw 'Name must be a string';
                if (value.length < 2 || value.length > 20)
                    throw 'Name must be 2-20 characters long.';
                name = value;
            };
        };
    
        // public static
        cls.get_nextId = function () {
            return nextId;
        };
    
        // public (shared across instances)
        cls.prototype = {
            announce: function () {
                alert('Hi there! My id is ' + this.get_id() + ' and my name is "' + this.get_name() + '"!\r\n' +
                      'The next fellow\'s id will be ' + MyClass.get_nextId() + '!');
            }
        };
    
        return cls;
    })();
    

    我被问到使用这个模式继承的问题,下面是:

    // It's a good idea to have a utility class to wire up inheritance.
    function inherit(cls, superCls) {
        // We use an intermediary empty constructor to create an
        // inheritance chain, because using the super class' constructor
        // might have side effects.
        var construct = function () {};
        construct.prototype = superCls.prototype;
        cls.prototype = new construct;
        cls.prototype.constructor = cls;
        cls.super = superCls;
    }
    
    var MyChildClass = (function () {
        // constructor
        var cls = function (surName) {
            // Call super constructor on this instance (any arguments
            // to the constructor would go after "this" in call(…)).
            this.constructor.super.call(this);
    
            // Shadowing instance properties is a little bit less
            // intuitive, but can be done:
            var getName = this.get_name;
    
            // public (this instance only)
            this.get_name = function () {
                return getName.call(this) + ' ' + surName;
            };
        };
        inherit(cls, MyClass); // <-- important!
    
        return cls;
    })();
    

    以及一个使用它的例子:

    var bob = new MyClass();
    bob.set_name('Bob');
    bob.announce(); // id is 1, name shows as "Bob"
    
    var john = new MyChildClass('Doe');
    john.set_name('John');
    john.announce(); // id is 2, name shows as "John Doe"
    
    alert(john instanceof MyClass); // true
    

    如您所见,这些类彼此正确地交互(它们共享来自 MyClass , the announce 方法使用正确的 get_name 方法等)

    需要注意的一点是需要隐藏实例属性。你真的可以 inherit 函数遍历所有实例属性(使用 hasOwnProperty )这是函数,并自动添加 super_<method name> 财产。这样你就可以打电话了 this.super_get_name() 而不是将其存储在临时值中并使用 call .

    对于原型上的方法,您不需要担心上面的问题,但是,如果您想要访问超级类的原型方法,您可以调用 this.constructor.super.prototype.methodName . 如果您想让它不那么冗长,当然可以添加便利属性。:)

        3
  •  166
  •   Jon    11 年前

    在我看来,你们大多数人都在举getter和setter的例子,而不是构造函数。 http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming) .

    吃过午饭的丹离我们更近了,但这个例子在jsiddle中不起作用。

    这个例子创建了一个只在对象创建期间运行的私有构造函数函数。

    var color = 'black';
    
    function Box()
    {
       // private property
       var color = '';
    
       // private constructor 
       var __construct = function() {
           alert("Object Created.");
           color = 'green';
       }()
    
       // getter
       this.getColor = function() {
           return color;
       }
    
       // setter
       this.setColor = function(data) {
           color = data;
       }
    
    }
    
    var b = new Box();
    
    alert(b.getColor()); // should be green
    
    b.setColor('orange');
    
    alert(b.getColor()); // should be orange
    
    alert(color); // should be black
    

    如果要分配公共属性,则可以将构造函数定义为:

    var color = 'black';
    
    function Box()
    {
       // public property
       this.color = '';
    
       // private constructor 
       var __construct = function(that) {
           alert("Object Created.");
           that.color = 'green';
       }(this)
    
       // getter
       this.getColor = function() {
           return this.color;
       }
    
       // setter
       this.setColor = function(color) {
           this.color = color;
       }
    
    }
    
    var b = new Box();
    
    alert(b.getColor()); // should be green
    
    b.setColor('orange'); 
    
    alert(b.getColor()); // should be orange
    
    alert(color); // should be black
    
        4
  •  23
  •   Joost Diepenmaat    14 年前

    那么“构造函数”的意义何在? 财产?不知道它在哪里 可能有用,有什么想法吗?

    构造器属性的要点是提供一些假装javascript具有类的方法。其中一件事就是你 不能 有效的做法是在创建对象后更改其构造函数。这很复杂。

    几年前我写了一篇相当全面的文章: http://joost.zeekat.nl/constructors-considered-mildly-confusing.html

        5
  •  16
  •   bitlather    11 年前

    例子如下: http://jsfiddle.net/FZ5nC/

    尝试此模板:

    <script>
    //============================================================
    // Register Namespace
    //------------------------------------------------------------
    var Name = Name||{};
    Name.Space = Name.Space||{};
    
    //============================================================
    // Constructor - MUST BE AT TOP OF FILE
    //------------------------------------------------------------
    Name.Space.ClassName = function Name_Space_ClassName(){}
    
    //============================================================
    // Member Functions & Variables
    //------------------------------------------------------------
    Name.Space.ClassName.prototype = {
      v1: null
     ,v2: null
     ,f1: function Name_Space_ClassName_f1(){}
    }
    
    //============================================================
    // Static Variables
    //------------------------------------------------------------
    Name.Space.ClassName.staticVar = 0;
    
    //============================================================
    // Static Functions
    //------------------------------------------------------------
    Name.Space.ClassName.staticFunc = function Name_Space_ClassName_staticFunc(){
    }
    </script>
    

    如果要定义静态类,则必须调整命名空间:

    <script>
    //============================================================
    // Register Namespace
    //------------------------------------------------------------
    var Shape = Shape||{};
    Shape.Rectangle = Shape.Rectangle||{};
    // In previous example, Rectangle was defined in the constructor.
    </script>
    

    实例类:

    <script>
    //============================================================
    // Register Namespace
    //------------------------------------------------------------
    var Shape = Shape||{};
    
    //============================================================
    // Constructor - MUST BE AT TOP OF FILE
    //------------------------------------------------------------
    Shape.Rectangle = function Shape_Rectangle(width, height, color){
        this.Width = width;
        this.Height = height;
        this.Color = color;
    }
    
    //============================================================
    // Member Functions & Variables
    //------------------------------------------------------------
    Shape.Rectangle.prototype = {
      Width: null
     ,Height: null
     ,Color: null
     ,Draw: function Shape_Rectangle_Draw(canvasId, x, y){
        var canvas = document.getElementById(canvasId);
        var context = canvas.getContext("2d");
        context.fillStyle = this.Color;
        context.fillRect(x, y, this.Width, this.Height);
     }
    }
    
    //============================================================
    // Static Variables
    //------------------------------------------------------------
    Shape.Rectangle.Sides = 4;
    
    //============================================================
    // Static Functions
    //------------------------------------------------------------
    Shape.Rectangle.CreateSmallBlue = function Shape_Rectangle_CreateSmallBlue(){
        return new Shape.Rectangle(5,8,'#0000ff');
    }
    Shape.Rectangle.CreateBigRed = function Shape_Rectangle_CreateBigRed(){
        return new Shape.Rectangle(50,25,'#ff0000');
    }
    </script>
    

    示例实例化:

    <canvas id="painting" width="500" height="500"></canvas>
    <script>
    alert("A rectangle has "+Shape.Rectangle.Sides+" sides.");
    
    var r1 = new Shape.Rectangle(16, 12, "#aa22cc");
    r1.Draw("painting",0, 20);
    
    var r2 = Shape.Rectangle.CreateSmallBlue();
    r2.Draw("painting", 0, 0);
    
    Shape.Rectangle.CreateBigRed().Draw("painting", 10, 0);
    </script>
    

    注意函数被定义为a.b=函数a_b()。这是为了使脚本更容易调试。打开chrome的inspect element面板,运行此脚本,然后展开debug backtrace:

    <script>
    //============================================================
    // Register Namespace
    //------------------------------------------------------------
    var Fail = Fail||{};
    
    //============================================================
    // Static Functions
    //------------------------------------------------------------
    Fail.Test = function Fail_Test(){
        A.Func.That.Does.Not.Exist();
    }
    
    Fail.Test();
    </script>
    
        6
  •  10
  •   Ry- Vincenzo Alcamo    12 年前

    这是一个构造函数:

    function MyClass() {}
    

    当你这样做的时候

    var myObj = new MyClass();
    

    MyClass 执行,并返回该类的新对象。

        7
  •  8
  •   anasanjaria    12 年前

    我发现这个教程非常有用。大多数jquery插件都使用这种方法。

    http://www.htmlgoodies.com/html5/tutorials/create-an-object-oriented-javascript-class-constructor.html#fbid=OVYAQL_TDpK

    var Class = function(methods) {   
        var klass = function() {    
            this.initialize.apply(this, arguments);          
        };  
    
        for (var property in methods) { 
           klass.prototype[property] = methods[property];
        }
    
        if (!klass.prototype.initialize) klass.prototype.initialize = function(){};      
    
        return klass;    
    };
    

    现在,

    var Person = Class({ 
        initialize: function(name, age) {
            this.name = name;
            this.age  = age;
        },
        toString: function() {
            return "My name is "+this.name+" and I am "+this.age+" years old.";
        }
    }); 
    
    var alice = new Person('Alice', 26);
    alert(alice.name); //displays "Alice"
    alert(alice.age); //displays "26"
    alert(alice.toString()); //displays "My name is Alice and I am 26 years old" in most browsers.
    //IE 8 and below display the Object's toString() instead! "[Object object]"
    
        8
  •  8
  •   bob    9 年前

    这种模式对我很有帮助。使用这种模式,您可以在单独的文件中创建类,并根据需要将它们加载到整个应用程序中。

    // Namespace
    // (Creating new if not instantiated yet, otherwise, use existing and just add to it)
    var myApp = myApp || {};
    
    // "Package" 
    // Similar to how you would establish a package in other languages
    (function() {
    
    // "Class"
    var MyClass = function(params) {
        this.initialize(params);
    }
    
        // "Private Static" vars 
        //    - Only accessible to functions in this class.
        //    - Doesn't get wiped out when we create a new instance.
        var countInstances = 0;
        var allInstances = [];
    
        // "Private Static" functions 
        //    - Same as above, but it's a function accessible 
        //      only to other functions in this class.
        function doSomething(){
        }
    
        // "Public Static" vars
        //    - Everyone has access.
        //    - Doesn't get wiped out when we create a new instance.
        MyClass.counter = 0;
    
        // "Public Static" functions
        //    - Same as above, but anyone can call this "static method".
        //    - Kinda like a singleton class situation.
        MyClass.foobar = function(){
        }
    
        // Public properties and methods are built into the "prototype"
        //    - This is how each instance can become unique unto itself.
        //    - Establishing "p" as "local" (Static Private) variable 
        //      simply so we don't have to keep typing "MyClass.prototype" 
        //      for each property and function.
    var p = MyClass.prototype;
    
        // "Public" vars
        p.id = null;
        p.firstname = null;
        p.lastname = null;
    
        // "Private" vars
        //    - Only used by "this" instance.
        //    - There isn't "true" privacy for each 
        //      instance so we have to fake it. 
        //    - By tradition, we indicate "privacy"  
        //      by prefixing it with an underscore. 
        //    - So technically, anyone can access, but we simply 
        //      don't tell anyone about it (e.g. in your API)
        //      so no one knows about it :)
        p._foo = null;
    
        p.initialize = function(params){
            this.id = MyClass.counter++;
            this.firstname = params.firstname;
            this.lastname = params.lastname;
            MyClass.counter++;
            countInstances++;
            allInstances.push(this);
        }
    
        p.doAlert = function(theMessage){
            alert(this.firstname + " " + this.lastname + " said: " + theMessage + ". My id:" + this.id + ".  Total People:" + countInstances + ". First Person:" + allInstances[0].firstname + " " + allInstances[0].lastname);
        }
    
    
    // Assign class to app
    myApp.MyClass = MyClass;
    
    // Close the "Package"
    }());
    
    // Usage example:
    var bob = new myApp.MyClass({   firstname   :   "bob",
                                    lastname    :   "er"
                                });
    
    bob.doAlert("hello there");
    
        9
  •  8
  •   Bruno    9 年前

    是的,可以这样定义类声明中的构造函数:

    class Rectangle {
      constructor(height, width) {
        this.height = height;
        this.width = width;
      }
    }
    
        10
  •  6
  •   O.O    13 年前

    我想我会发布我对JavaScript闭包所做的,因为还没有人使用闭包。

    var user = function(id) {
      // private properties & methods goes here.
      var someValue;
      function doSomething(data) {
        someValue = data;
      };
    
      // constructor goes here.
      if (!id) return null;
    
      // public properties & methods goes here.
      return {
        id: id,
        method: function(params) {
          doSomething(params);
        }
      };
    };
    

    欢迎对此解决方案提出意见和建议。:)

        11
  •  4
  •   Dan Power    13 年前

    使用上面的尼克示例,可以为对象创建一个构造函数 没有 使用返回语句作为对象定义中的最后一条语句的参数。按如下所示返回构造函数函数,它将在每次创建对象时运行\构造中的代码:

    function Box()
    {
       var __construct = function() {
           alert("Object Created.");
           this.color = 'green';
       }
    
      this.color = '';
    
       this.getColor = function() {
           return this.color;
       }
    
       __construct();
    }
    
    var b = new Box();
    
        12
  •  3
  •   Simon_Weaver    11 年前

    如果你用的话 Typescript -从Microsoft打开源代码:-)

    class BankAccount {
     balance: number;
     constructor(initially: number) {
     this.balance = initially;
     }
     deposit(credit: number) {
     this.balance += credit;
     return this.balance;
     }
    }
    

    typescript允许您“伪造”被编译成javascript构造的OO构造。如果您正在启动一个大型项目,它可能会节省您很多时间,并且它刚刚达到里程碑1.0版本。

    http://www.typescriptlang.org/Content/TypeScript%20Language%20Specification.pdf

    以上代码将“编译”为:

    var BankAccount = (function () {
        function BankAccount(initially) {
            this.balance = initially;
        }
        BankAccount.prototype.deposit = function (credit) {
            this.balance += credit;
            return this.balance;
        };
        return BankAccount;
    })();
    
        13
  •  3
  •   Just Rudy    7 年前

    也许会简单一点,但下面是我在2017年提出的建议:

    class obj {
      constructor(in_shape, in_color){
        this.shape = in_shape;
        this.color = in_color;
      }
    
      getInfo(){
        return this.shape + ' and ' + this.color;
      }
      setShape(in_shape){
        this.shape = in_shape;
      }
      setColor(in_color){
        this.color = in_color;
      }
    }
    

    在使用上面的类时,我有以下内容:

    var newobj = new obj('square', 'blue');
    
    //Here, we expect to see 'square and blue'
    console.log(newobj.getInfo()); 
    
    newobj.setColor('white');
    newobj.setShape('sphere');
    
    //Since we've set new color and shape, we expect the following: 'sphere and white'
    console.log(newobj.getInfo());
    

    如您所见,构造函数接受两个参数,我们设置了对象的属性。我们还通过使用 setter 函数,并证明其在调用时仍保持更改 getInfo() 在这些变化之后。

    有点晚了,但我希望这有帮助。我用一个 mocha 单元测试,而且工作正常。

        14
  •  1
  •   Dmitri Pavlutin    9 年前

    在javascript中,调用类型定义函数的行为:

    • 直接调用 func()
    • 对象上的方法调用 obj.func()
    • 构造函数 调用 new func()
    • 间接调用 func.call() func.apply()

    函数作为 构造函数 调用时使用 new 操作员:

    function Cat(name) {
       this.name = name;
    }
    Cat.prototype.getName = function() {
       return this.name;
    }
    
    var myCat = new Cat('Sweet'); // Cat function invoked as a constructor
    

    javascript中的任何实例或原型对象都有一个属性 constructor ,表示构造函数函数。

    Cat.prototype.constructor === Cat // => true
    myCat.constructor         === Cat // => true
    

    检查 this post 关于构造函数属性。

        15
  •  0
  •   jan    11 年前

    当从上面使用Blixt的伟大模板时,我发现它在多层继承(MyGrandChildClass扩展MyChildClass扩展MyClass)中不能很好地工作,它反复调用第一个父类的构造函数。因此,如果您需要多层次继承,而不是使用 this.constructor.super.call(this, surName); 使用 chainSuper(this).call(this, surName); 链函数的定义如下:

    function chainSuper(cls) {
      if (cls.__depth == undefined) cls.__depth = 1; else cls.__depth++;
      var depth = cls.__depth;
      var sup = cls.constructor.super;
      while (depth > 1) {
        if (sup.super != undefined) sup = sup.super;
        depth--;
      }
      return sup;
    }
    
        16
  •  0
  •   user1624059    10 年前

    http://www.jsoops.net/ 在JS中非常适合OOP。如果提供private、protected、public变量和函数,以及继承功能。示例代码:

    var ClassA = JsOops(function (pri, pro, pub)
    {// pri = private, pro = protected, pub = public
    
        pri.className = "I am A ";
    
        this.init = function (var1)// constructor
        {
            pri.className += var1;
        }
    
        pub.getData = function ()
        {
            return "ClassA(Top=" + pro.getClassName() + ", This=" + pri.getClassName()
            + ", ID=" + pro.getClassId() + ")";
        }
    
        pri.getClassName = function () { return pri.className; }
        pro.getClassName = function () { return pri.className; }
        pro.getClassId = function () { return 1; }
    });
    
    var newA = new ClassA("Class");
    
    //***Access public function
    console.log(typeof (newA.getData));
    // function
    console.log(newA.getData());
    // ClassA(Top=I am A Class, This=I am A Class, ID=1)
    
    //***You can not access constructor, private and protected function
    console.log(typeof (newA.init));            // undefined
    console.log(typeof (newA.className));       // undefined
    console.log(typeof (newA.pro));             // undefined
    console.log(typeof (newA.getClassName));    // undefined
    
        17
  •  0
  •   dss    10 年前

    只是提供一些多样性。 ds.oop 是用JavaScript中的构造函数声明类的好方法。它支持所有可能的继承类型(包括1个甚至C都不支持的类型)以及很好的接口。

    var Color = ds.make.class({
        type: 'Color',
        constructor: function (r,g,b) { 
            this.r = r;                     /* now r,g, and b are available to   */
            this.g = g;                     /* other methods in the Color class  */
            this.b = b;                     
        }
    });
    var red = new Color(255,0,0);   // using the new keyword to instantiate the class
    
        18
  •  0
  •   Sheo Dayal Singh    7 年前

    这里我们需要注意Java脚本中的一个点,它是一个无类语言,但是,我们可以通过使用Java脚本中的函数来实现它。最常见的实现方法是,我们需要在Java脚本中创建一个函数并使用 新的 关键字 创建对象并使用 关键字 定义属性和方法。下面是示例。

    // Function constructor
    
       var calculator=function(num1 ,num2){
       this.name="This is function constructor";
       this.mulFunc=function(){
          return num1*num2
       };
    
    };
    
    var objCal=new calculator(10,10);// This is a constructor in java script
    alert(objCal.mulFunc());// method call
    alert(objCal.name);// property call
    
    //Constructors With Prototypes
    
    var calculator=function(){
       this.name="Constructors With Prototypes";
    };
    
    calculator.prototype.mulFunc=function(num1 ,num2){
     return num1*num2;
    };
    var objCal=new calculator();// This is a constructor in java script
    alert(objCal.mulFunc(10,10));// method call
    alert(objCal.name); // property call
    
        19
  •  -2
  •   Coded Container    9 年前

    在大多数情况下,在调用传递此信息的方法之前,必须以某种方式声明所需的属性。如果最初不需要设置属性,可以这样在对象内调用方法。也许这不是最漂亮的方法,但这仍然有效。

    var objectA = {
        color: ''; 
        callColor : function(){
            console.log(this.color);
        }
        this.callColor(); 
    }
    var newObject = new objectA();