我知道这会奏效:
function Foo() {};
Foo.prototype.talk = function () {
alert('hello~\n');
};
var a = new Foo;
a.talk(); // 'hello~\n'
但如果我想打电话
Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly
我找到了一些让Foo.talk
工作的方法,
Foo.__proto__ = Foo.prototype
Foo.talk = Foo.prototype.talk
还有其他方法吗?我不知道这样做是否正确。您是否在JavaScript代码中使用了类方法或静态方法?
答案 0 :(得分:373)
首先,请记住JavaScript主要是prototypal language,而不是class-based language 1 。 Foo
不是一个类,它是一个函数,它是一个对象。您可以使用new
关键字从实例化该对象,这将允许您使用标准OOP语言创建类似于类的内容。
我建议大多数时候忽略__proto__
,因为它的浏览器支持较差,而是专注于了解prototype
的工作原理。
如果你有一个从函数 2 创建的对象的实例,并且你以任何方式访问它的一个成员(方法,属性,属性,常量等),那么访问将会向下流动原型层次结构,直到它(a)找到成员,或(b)找不到另一个原型。
层次结构从被调用的对象开始,然后搜索其原型对象。如果原型对象有原型,则重复,如果不存在原型,则返回undefined
。
例如:
foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"
foo = {};
console.log(foo.bar); // logs undefined
function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set
在我看来,你已经至少在某种程度上理解了这些“基本”部分,但我需要明确这些部分才能确定。
在JavaScript中,一切都是对象 3 。
一切是一个对象。
function Foo(){}
不只是定义一个新函数,它定义了一个可以使用Foo
访问的新函数对象。
这就是您可以使用Foo
访问Foo.prototype
原型的原因。
您还可以在Foo
上设置更多功能:
Foo.talk = function () {
alert('hello world!');
};
可以使用以下方法访问此新功能:
Foo.talk();
我希望到现在你注意到函数对象和静态方法的函数之间的相似性。
将f = new Foo();
视为创建类实例,将Foo.prototype.bar = function(){...}
视为定义类的共享方法,将Foo.baz = function(){...}
视为为类定义公共静态方法。
ECMAScript 2015为这些类型的声明引入了各种语法糖,使其更易于实现,同时更易于阅读。因此,前面的示例可以写为:
class Foo {
bar() {...}
static baz() {...}
}
允许将bar
称为:
const f = new Foo()
f.bar()
和baz
被称为:
Foo.baz()
1:class
was a "Future Reserved Word" in the ECMAScript 5 specification,但ES6引入了使用class
关键字定义类的功能。
2:本质上是一个由构造函数创建的类实例,但有许多细微差别,我不想误导你
3:primitive values - 包括undefined
,null
,布尔值,数字和字符串 - 技术上不是对象,因为它们是低级语言实现。布尔值,数字和字符串仍然与原型链相互作用,就像它们是对象一样,所以为了这个答案的目的,即使它们不完整,也更容易将它们视为“对象”。
答案 1 :(得分:65)
您可以按照以下方式实现:
function Foo() {};
Foo.talk = function() { alert('I am talking.'); };
您现在可以调用" talk"功能如下:
Foo.talk();
您可以这样做,因为在JavaScript中,函数也是对象。 " zzzzBov"我也回答了这个问题,但这是一个冗长的阅读。
答案 2 :(得分:35)
从实例调用静态方法:
function Clazz() {};
Clazz.staticMethod = function() {
alert('STATIC!!!');
};
Clazz.prototype.func = function() {
this.constructor.staticMethod();
}
var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"
简单的Javascript类项目:https://github.com/reduardo7/sjsClass
答案 3 :(得分:30)
这是一个很好的例子来演示Javascript如何使用静态/实例变量和方法。
function Animal(name) {
Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
this.name = name; //instance variable, using "this"
}
Animal.showCount = function () {//static method
alert(Animal.count)
}
Animal.prototype.showName=function(){//instance method
alert(this.name);
}
var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");
Animal.showCount(); // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from Java
答案 4 :(得分:25)
此外,现在可以使用class
和static
'use strict'
class Foo {
static talk() {
console.log('talk')
};
speak() {
console.log('speak')
};
};
将给出
var a = new Foo();
Foo.talk(); // 'talk'
a.talk(); // err 'is not a function'
a.speak(); // 'speak'
Foo.speak(); // err 'is not a function'
答案 5 :(得分:10)
我使用命名空间:
var Foo = {
element: document.getElementById("id-here"),
Talk: function(message) {
alert("talking..." + message);
},
ChangeElement: function() {
this.element.style.color = "red";
}
};
使用它:
Foo.Talk("Testing");
或
Foo.ChangeElement();
答案 6 :(得分:5)
ES6现在支持class
&amp; static
关键字如魅力:
class Foo {
constructor() {}
talk() {
console.log("i am not static");
}
static saying() {
console.log(this.speech);
}
static get speech() {
return "i am static method";
}
}
答案 7 :(得分:2)
如果你必须在ES5中编写静态方法,我找到了一个很棒的教程:
//Constructor
var Person = function (name, age){
//private properties
var priv = {};
//Public properties
this.name = name;
this.age = age;
//Public methods
this.sayHi = function(){
alert('hello');
}
}
// A static method; this method only
// exists on the class and doesn't exist
// on child objects
Person.sayName = function() {
alert("I am a Person object ;)");
};
请参阅@ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/
答案 8 :(得分:1)
当您尝试调用Foo.talk
时,JS会尝试通过talk
搜索函数__proto__
,当然,无法找到它。
Foo.__proto__
是Function.prototype
。
答案 9 :(得分:1)
仅需补充说明。使用类ES6,当我们创建静态方法时。.Javacsript引擎将描述符属性设置为与老式的“静态”方法不同的一点
function Car() {
}
Car.brand = function() {
console.log('Honda');
}
console.log(
Object.getOwnPropertyDescriptors(Car)
);
它将brand()的内部属性(描述符属性)设置为
..
brand: [object Object] {
configurable: true,
enumerable: true,
value: ..
writable: true
}
..
相比
class Car2 {
static brand() {
console.log('Honda');
}
}
console.log(
Object.getOwnPropertyDescriptors(Car2)
);
将brand()的内部属性设置为
..
brand: [object Object] {
configurable: true,
enumerable: false,
value:..
writable: true
}
..
看到ES6中的静态方法将可枚举设置为 false 。
这意味着您不能使用for-in循环来检查对象
for (let prop in Car) {
console.log(prop); // brand
}
for (let prop in Car2) {
console.log(prop); // nothing here
}
ES6中的静态方法与其他人的类私有属性(名称,长度,构造函数)一样,只是静态方法仍可写,因此描述符 writable 设置为 true { writable: true }
。这也意味着我们可以覆盖它
Car2.brand = function() {
console.log('Toyota');
};
console.log(
Car2.brand() // is now changed to toyota
);
答案 10 :(得分:0)
在您的情况下,如果您想要Foo.talk()
:
function Foo() {};
// But use Foo.talk would be inefficient
Foo.talk = function () {
alert('hello~\n');
};
Foo.talk(); // 'hello~\n'
但这是一种低效的实施方式,使用prototype
会更好。
另一种方式,我的方式被定义为静态类:
var Foo = new function() {
this.talk = function () {
alert('hello~\n');
};
};
Foo.talk(); // 'hello~\n'
上面的静态类不需要使用prototype
,因为它只会作为静态用法构造一次。
https://github.com/yidas/js-design-patterns/tree/master/class
答案 11 :(得分:0)
当我遇到这样的情况时,我做了类似的事情:
Logger = {
info: function (message, tag) {
var fullMessage = '';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.log(fullMessage);
}
},
warning: function (message, tag) {
var fullMessage = '';
fullMessage = this._getFormatedMessage(message, tag);
if (loggerEnabled) {
console.warn(fullMessage);`enter code here`
}
},
_getFormatedMessage: function () {}
};
所以现在我可以将info方法称为
Logger.info("my Msg", "Tag");
答案 12 :(得分:0)
静态方法调用直接在类上进行,并且在类的实例上不可调用。静态方法经常被用来 创建效用函数
非常清晰的描述
Taken Directly from mozilla.org
Foo需要绑定到你的班级 然后,当您创建一个新实例时,您可以调用myNewInstance.foo() 如果您导入了类,则可以调用静态方法
答案 13 :(得分:0)
JavaScript没有实际的类,而是使用原型继承系统,其中对象通过其原型链从其他对象“继承”。最好通过代码本身来解释:
function Foo() {};
// creates a new function object
Foo.prototype.talk = function () {
console.log('hello~\n');
};
// put a new function (object) on the prototype (object) of the Foo function object
var a = new Foo;
// When foo is created using the new keyword it automatically has a reference
// to the prototype property of the Foo function
// We can show this with the following code
console.log(Object.getPrototypeOf(a) === Foo.prototype);
a.talk(); // 'hello~\n'
// When the talk method is invoked it will first look on the object a for the talk method,
// when this is not present it will look on the prototype of a (i.e. Foo.prototype)
// When you want to call
// Foo.talk();
// this will not work because you haven't put the talk() property on the Foo
// function object. Rather it is located on the prototype property of Foo.
// We could make it work like this:
Foo.sayhi = function () {
console.log('hello there');
};
Foo.sayhi();
// This works now. However it will not be present on the prototype chain
// of objects we create out of Foo
答案 14 :(得分:0)
在函数或类对象以及它们的实例上实现了方法和属性的树方式。
Foo.method()
或 Foo.prop
。这些是静态方法或属性Foo.prototype.method()
或 Foo.prototype.prop
。创建时,实例将通过原型女巫 {method:function(){...}, prop:...}
继承这些对象。所以 foo 对象将接收作为原型的 Foo.prototype 对象的副本。foo={method:function(){...}, prop:...}
this
关键字将根据上下文进行不同的表示和操作。在静态方法中,它将代表类本身(毕竟 witch 是 Function 的一个实例:class Foo {}
相当于 let Foo = new Function({})
使用 ECMAScript 2015,在今天看来实现得很好,可以更清楚地看到类(静态)方法和属性、实例方法和属性以及自己的方法和属性之间的区别。因此,您可以创建三个名称相同但不同的方法或属性,因为它们适用于不同的对象,方法中的 this
关键字将分别适用于类对象自身和实例对象,由原型或由它自己。
class Foo {
constructor(){super();}
static prop = "I am static" // see 1.
static method(str) {alert("static method"+str+" :"+this.prop)} // see 1.
prop="I am of an instance"; // see 2.
method(str) {alert("instance method"+str+" : "+this.prop)} // see 2.
}
var foo= new Foo();
foo.prop = "I am of own"; // see 3.
foo.func = function(str){alert("own method" + str + this.prop)} // see 3.