我知道这是可行的:

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的方法。谈工作,

Foo。__proto__ = Foo.prototype Foo。talk = Foo.prototype.talk

还有别的办法吗?我不知道这样做是否正确。在JavaScript代码中使用类方法还是静态方法?


当前回答

首先,请记住JavaScript主要是一种原型语言,而不是基于类的语言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中,所有东西都是object3。

一切都是一个对象。

function Foo(){}不仅定义了一个新函数,它还定义了一个可以使用Foo访问的新函数对象。

这就是为什么你可以用Foo.prototype访问Foo的原型。

你还可以在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在ECMAScript 5规范中是一个“未来保留字”,但ES6引入了使用class关键字定义类的能力。

2:本质上是一个由构造函数创建的类实例,但有许多微妙的区别,我不想误导你

3:基本值——包括未定义、null、布尔值、数字和字符串——在技术上不是对象,因为它们是低级语言实现。布尔值、数字和字符串仍然与原型链交互,就像它们是对象一样,因此为了回答这个问题,更容易将它们视为“对象”,尽管它们不完全是。

其他回答

我使用命名空间:

var Foo = {
     element: document.getElementById("id-here"),

     Talk: function(message) {
            alert("talking..." + message);
     },

     ChangeElement: function() {
            this.element.style.color = "red";
     }
};

要使用它:

Foo.Talk("Testing");

Or

Foo.ChangeElement();

ES6现在支持类和静态关键字,就像一个魅力:

class Foo {
    constructor() {}

    talk() {
        console.log("i am not static");
    }

    static saying() {
        console.log(this.speech);
    }

    static get speech() {
        return "i am static method";
    }

}

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

首先,请记住JavaScript主要是一种原型语言,而不是基于类的语言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中,所有东西都是object3。

一切都是一个对象。

function Foo(){}不仅定义了一个新函数,它还定义了一个可以使用Foo访问的新函数对象。

这就是为什么你可以用Foo.prototype访问Foo的原型。

你还可以在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在ECMAScript 5规范中是一个“未来保留字”,但ES6引入了使用class关键字定义类的能力。

2:本质上是一个由构造函数创建的类实例,但有许多微妙的区别,我不想误导你

3:基本值——包括未定义、null、布尔值、数字和字符串——在技术上不是对象,因为它们是低级语言实现。布尔值、数字和字符串仍然与原型链交互,就像它们是对象一样,因此为了回答这个问题,更容易将它们视为“对象”,尽管它们不完全是。

在函数或类对象以及它们的实例上实现方法和属性有很多方法。

在类(或函数)本身:Foo.method()或Foo.prop。这些是静态方法或属性 在它的原型上:Foo.prototype.method()或Foo.prototype.prop。创建时,实例将通过原型女巫{method:function(){…},道具:…}。所以foo对象会接收,作为原型,一个foo的副本。原型对象。 在实例本身上:将方法或属性添加到对象本身。foo ={方法:函数(){…},道具:}

this关键字将根据上下文以不同的方式表示和执行。在静态方法中,它将代表类本身(witch毕竟是Function的一个实例:类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.