JavaScript对象中的构造函数
JavaScript类/对象可以有构造函数吗? 他们是如何创build的?
使用原型:
function Box(color) // Constructor { this.color = color; } Box.prototype.getColor = function() { return this.color; };
隐藏“颜色”(有点类似私人成员variables):
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
这里有一个模板,我有时在JavaScript中用于OOP类似的行为。 正如你所看到的,你可以使用闭包模拟私有(静态和实例)成员。 什么new MyClass()
将返回一个只有属性分配给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; })();
我已经被问及使用这种模式的inheritance,所以在这里:
// 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
的静态ID, announce
方法使用正确的get_name
方法等)
有一件事要注意的是需要阴影实例属性。 实际上,可以使inherit
函数遍历所有作为函数的实例属性(使用hasOwnProperty
),并自动添加一个super_<method name>
属性。 这会让你调用this.super_get_name()
而不是将其存储在一个临时值中,并使用call
调用它。
对于原型上的方法,你不需要担心上述情况,如果你想访问超类的原型方法,你可以调用this.constructor.super.prototype.methodName
。 如果你想减less冗长,你当然可以添加便利性。 🙂
在我看来,你们大多数人都给了getter和setter的例子,而不是一个构造函数,例如http://en.wikipedia.org/wiki/Constructor_(object-oriented_programming); 。
午餐更近了,但是这个例子在jsFiddle中没有用。
这个例子创build了一个私有构造函数,它只在对象的创build过程中运行。
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
那么“构造函数”属性是什么? 无法弄清楚哪里有用,有什么想法?
构造函数属性的要点是提供一些假装JavaScript的方法。 你不能有用的事情之一就是在创build对象的构造函数之后进行修改。 这很复杂。
几年前我写了一篇相当全面的文章: http : //joost.zeekat.nl/constructors-considered-mildly-confusing.html
示例: 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>
通知函数被定义为AB =函数A_B()。 这是为了使您的脚本更易于debugging。 打开Chrome的Inspect Element面板,运行这个脚本,并展开debugging回溯:
<script> //============================================================ // Register Namespace //------------------------------------------------------------ var Fail = Fail||{}; //============================================================ // Static Functions //------------------------------------------------------------ Fail.Test = function Fail_Test(){ A.Func.That.Does.Not.Exist(); } Fail.Test(); </script>
这是一个构造函数:
function MyClass() {}
当你这样做
var myObj = new MyClass();
MyClass
被执行,并且该类的一个新对象被返回。
我发现这个教程非常有用。 这种方法被大多数jQuery插件所使用。
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]"
这种模式对我很好。 使用这种模式,您可以在单独的文件中创build类,并根据需要将其加载到整个应用程序中。
// 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 (eg 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");
是的,您可以在类声明中定义一个构造函数,如下所示:
class Rectangle { constructor(height, width) { this.height = height; this.width = width; } }
我想我会发布我所做的closuresJavaScript,因为没有人使用闭包。
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); } }; };
欢迎对此解决scheme提出意见和build议。 🙂
使用上面的Nick示例,可以使用return语句作为对象定义中的最后一个语句,为不带参数的对象创build构造函数。 按照下面的方式返回你的构造函数,每次创build对象时它都会在__construct中运行代码:
function Box() { var __construct = function() { alert("Object Created."); this.color = 'green'; } this.color = ''; this.getColor = function() { return this.color; } __construct(); } var b = new Box();
他们这样做,如果你使用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; })();
在JavaScript中,调用types定义了函数的行为:
- 直接调用
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
检查这个职位关于构造函数属性。
从上面的使用Blixt伟大的模板时,我发现它不能很好地与多级inheritance(MyGrandChildClass扩展MyChildClass扩展MyClass) – 它循环调用第一个父母的构造函数一遍又一遍。 所以这里是一个简单的解决方法 – 如果你需要多级inheritance,而不是使用this.constructor.super.call(this, surName);
使用chainSuper(this).call(this, surName);
链function定义如下:
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; }
http://www.jsoops.net/在Js中是相当不错的。; 如果提供私有的,受保护的,公共variables和函数,并且还有inheritance特性。 示例代码:
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
只是为了提供一些变化。 ds.oop是在javascript中用构造函数声明类的一个好方法。 它支持所有可能的inheritancetypes(包括即使c#不支持的1种types)以及接口,这是很好的。
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
也许它变得更简单了,但下面是我现在在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
函数来改变对象的颜色和形状,并certificate在这些改变之后调用getInfo()
时它的改变仍然存在。
有点晚了,但我希望这有助于。 我已经用mocha
unit testingtesting过了,运行良好。
这里我们需要注意一点,在java脚本中,它是一个无类的语言,但是我们可以通过使用java脚本中的函数来实现它。 实现这个目标的最常用的方法是我们需要在java脚本中创build一个函数,并使用new 关键字来创build一个对象,并使用这个 关键字来定义属性和方法。下面是一个例子。
// 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
在大多数情况下,您必须以某种方式声明所需的属性,然后才能调用传递此信息的方法。 如果你不需要初始化一个属性,你可以像这样在对象中调用一个方法。 可能不是这样做的最漂亮的方式,但这仍然有效。
var objectA = { color: ''; callColor : function(){ console.log(this.color); } this.callColor(); } var newObject = new objectA();