我见过用这些不同的方式创建javascript类:
function Thing() {
method1: function() {
},
method2: function() {
}
}
方法1
var thing = {
method1: function() {
},
method2: function() {
}
};
方法2
function Thing() {
}
Thing.prototype.method1 = function() {
}
Thing.prototype.method2 = function() {
}
方法3 var thing = (function(){
var b={};
b.method1 = function(){
};
b.method2 = function class2(){
};
return b;
}());
方法4 这些不同的方法类的声明有名字吗?它们是什么?我还遗漏了什么方法吗?
首先,让我们看看你问的那些实际上不是创建类的方法的事情。
如果你只需要一个有方法的对象,而不需要类,你可以创建一个对象字面值。
var myObject = {
varname: value,
varname: value,
methodname: function() {
// do something
},
methodname: function() {
// do something
}
};
这很少有用,但是它用自己的变量创建一个实例,其中一些是函数。请注意,在JS中,属性和方法之间没有区别。方法只是一个类型为function
的属性。
使用var
关键字在函数内部创建的变量仅在函数内部可用。编写库的人经常以自执行函数的形式将整个代码封装在闭包中,这样代码末尾就不再存在任何临时变量:
(function(){
// code here
}());
现在要在JS中创建一个类,只需要创建一个构造函数。使用this
关键字可以在创建的实例中存储属性。
function MyClass(param) {
this.value = param;
}
var instance = new MyClass("example");
函数是存储在对象中的代码块。你可以像存储其他东西一样将函数存储在变量中,所以你也可以将函数存储在对象中。
function MyClass() {
this.myMethod = function() {
alert("hi");
};
}
但是,由于类的所有实例都需要运行相同的代码,因此在构造函数中创建函数的效率不高。这将为您创建的每个实例创建一个函数的新副本。因此,我们不这样做,而是将函数存储在对象的原型中。
无论何时输入instance.someproperty
, JS引擎都会查看instance
,看看它是否有一个名为someproperty
的属性。如果没有,它会尝试查看instance
的原型,看看它是否有该名称的属性。如果没有,它会尝试查看原型的原型……以此类推,直到到达链的顶端。
所以如果你将函数存储在MyClass.prototype.myMethod
中,你将能够用instance.myMethod
调用它,并且只有一个由所有实例共享的函数副本。
function MyClass(param) {
this.value = param;
}
MyClass.prototype.myMethod = function() {
alert(this.value);
};
将函数放在构造函数中而不是使用原型链有一个很好的理由:创建伪私有变量和getter/setter函数。
至于如何命名这两种将方法绑定到对象的方法,在构造函数内部声明的函数是特权方法,而用原型模式声明的函数称为公共方法。有人指出,Method 1是无效的js
。方法1应该写成
function thing() {
return {
method1: function(){},
method2: function(){}
}
}
被称为工厂函数,调用它(像任何普通函数一样)产生具有指定属性的对象。然而,每个对象都有自己的副本(这可能是不必要的),所以方法3将共享功能(方法,常量等)放入函数的原型中。通过调用该函数创建的所有对象(应该使用new
关键字调用,而不是工厂函数)都可以访问附加到其构造函数原型上的属性(但所有对象都共享指向同一属性的指针,而不是它们自己的副本)。
方法2只是创建一个具有所需属性的对象字面值,根本不是一个"类"。
方法4也不是一个真正的"类"(在任何意义上的术语),它被称为模块模式,并使用词法闭包来封装通过返回的对象/函数揭示公共API的功能。
同样值得重申的是,如上所述,这些都不是真正的类,ES 6class
关键字是方法3的语法糖。