JavaScript对象中的构造函数

JavaScript类/对象可以有构造函数吗?它们是如何产生的?

345799 次浏览

下面是一个模板,我有时会在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;
})();

有人问过我使用这种模式的继承问题,所以如下:

// 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。如果你想让它不那么冗长,你当然可以添加便利属性。:)

使用原型:

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

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

构造函数属性的目的是提供某种方式来假装JavaScript有类。不能有用的一件事是在创建对象后更改对象的构造函数。它是复杂的。

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

使用上面Nick的示例,您可以使用return语句作为对象定义中的最后一条语句为对象没有参数创建构造函数。返回你的构造函数,如下所示,它将在你每次创建对象时运行__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();

这是一个构造函数:

function MyClass() {}

当你这样做时

var myObj = new MyClass();

MyClass被执行,返回该类的一个新对象。

我想我会发布我用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);
}
};
};

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

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

lunch -dan更接近,但是这个例子在jsFiddle中不起作用。

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

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

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

// 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");

我发现这个教程非常有用。大多数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]"

示例: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 = function A_B()。这是为了使您的脚本更容易调试。打开Chrome的Inspect Element面板,运行这个脚本,并展开调试回溯:

<script>
//============================================================
// Register Namespace
//------------------------------------------------------------
var Fail = Fail||{};


//============================================================
// Static Functions
//------------------------------------------------------------
Fail.Test = function Fail_Test(){
A.Func.That.Does.Not.Exist();
}


Fail.Test();
</script>

在使用上面Blixt的伟大模板时,我发现它不能很好地使用多级继承(MyGrandChildClass扩展MyChildClass扩展MyClass)——它循环调用第一个父类的构造函数。因此,这里有一个简单的解决方案-如果你需要多级继承,而不是使用this.constructor.super.call(this, surName);,使用chainSuper(this).call(this, surName);和这样定义的chain函数:

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;
}

如果你使用微软开源的打印稿,他们就会这样做:-)

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

Typescript让你“伪造”OO结构,这些结构被编译成javascript结构。如果你正在开始一个大型项目,它可以为你节省很多时间,而且它刚刚达到里程碑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;
})();

http://www.jsoops.net/对于Js中的oop很好。提供私有、受保护、公共变量和函数,并具有继承特性。示例代码:

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中使用构造函数声明类的好方法。它支持所有可能的继承类型(包括一种甚至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

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

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

在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

检查这篇文章的构造函数属性。

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

class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}

也许它变得简单了一点,但以下是我在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单元测试测试了这个,它工作得很好。

这里我们需要注意一点,它是一种无类语言,但是我们可以通过使用java script中的函数来实现。实现这一点最常见的方法是,我们需要在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