ES6静态方法与非静态方法和ES5 OOP

时间:2018-03-29 06:09:35

标签: javascript oop ecmascript-6

我有点困惑。

如果,例如......:

selection = Integer.parseInt(in.nextLine())

如果上面的说法正确并且我说得对,那么为什么我需要静态函数呢?因为这个:

function Person(firstName, lastName){
    this.firstName = firstName;
    this.lastName = lastName;
}
// so, the following will be shared, and this 
// is the best practice, right?:
Person.prototype.whatEver = function(){
    return this.firstName + " " + this.lastName;
}
// the following will also be shared, but it's 
// bad practice, because it will be included in 
// each instances and take space(memory) for nothing. correct?
Person.whatEver = function(){
    return this.firstName + " " + this.lastName;
}

就是这样,对吗?:

Person.whatEver = function(){
    return this.firstName + " " + this.lastName;
}

4 个答案:

答案 0 :(得分:3)

虽然这相当于ES6静态方法,但它没有按照您的想法行事:

Person.whatEver = function(){
  return this.firstName + " " + this.lastName;
}

这会将whatEver函数放在Person 构造函数上,而不是放在实例化的person上 - 而Person构造函数可能没有firstNamelastName。你可能在考虑

const person = new Person();
person.whatEver = function(){
  return this.firstName + " " + this.lastName;
}

在这种情况下,是的,每次Person实例化时都会运行这样的代码,这将导致很多函数(每个人一个),而不是原型上的单个函数。

静态方法的使用通常是 与实例化对象的交互。想想您何时可能需要与类关联的信息,即使尚未实例化任何内容。例如,您可以在Person类上使用静态方法:

class Person {
  static canEat() {
    return ['apples', 'bananas', 'carrots'];
  }
  // ...

答案 1 :(得分:1)

  

以下内容也将被分享,但这是不好的做法,因为它将被包含在每个实例中并且不占用空间(内存)。正确的吗?

不,不会。您会看到JS中的方法被指定为对它们的引用。此方法将创建一次,不会对每个对象反复重复。他们会指出相同的方法。这只是一种静态方法。因此,whatEver函数的两个定义都是在Person类上静态定义它。

所以如果您有以下代码:

let firstPerson = new Person();
let secondPerson = new Person();

这两个对象都将引用相同的实例方法(原型1)whatEver。现在,Person.whatEver静态方法也将只有一个副本,只能在Person类上直接调用,而且没有此类的实例。

答案 2 :(得分:1)

//contstructor 
function Person () { … } 

//member method
Person.prototype.foo = function () { 
  console.log(this); 
}

//static method
Person.foo = function () { 
   console.log(this);
}

所有功能定义仅在内存中创建一次。差异是»这个背景«:

new Person().foo(); // [Object Person] or Person {}

Person.foo(); // Person () {}

这就是为什么你不能在静态函数中访问成员属性的原因。 this指的是不是实例的构造函数。在幕后,使用new运算符将执行以下操作:

var obj = Person.call({}) // a new Object is created and passed as the
                          // »this context« and automatically returned.

如果你有:

function Person () {
  this.bar = function () { … }
} 

将在Memory中为每个实例(new Person())创建一个新的函数对象,但这是原型链的特定属性。在实例上调用方法将导致JS解释器首先搜索所有“自己的”属性,然后上传原型链以查找所请求的属性。 prototype由所有实例共享,因此其属性仅创建一次。

在ES6中,它看起来像这样:

class Person(){

  static foo () {}

  constructor () {}

  bar () {}

}

答案 3 :(得分:1)

  

以下内容也将被分享,但这是不好的做法,   因为它将包含在每个实例中并采取   空间(记忆)什么都没有。正确的吗?

这是因为误解了函数在Javascript中的工作原理。

在基于class的语言中,当创建类的实例时,所有方法定义(包括继承的方法定义)都被复制

Javascript不是基于class

ES6添加了class支持,但它只是一个糖,javascript class并不像Java或C ++中的类(或大多数其他{{1} } ic语言)

Java或C ++中的

class方法并不需要实例化,这可能非常有用。

在Javascript中,由于没有类或类的实例化,因此不会复制这些方法。 只复制对函数的引用。

在您的代码中

static

为了便于理解,您可以将Person.whatEver = function(){ return this.firstName + " " + this.lastName; } 视为具有函数Person的对象。所以你的静态'

与上述方法并无太大区别
whatEver

例如,您可以在没有实例化的情况下调用let Person = { whatEver() { return this.firstName + " " + this.lastName; }, talk() { return 'I can talk'; }, };

但是,对于Person.talk()函数,如果您需要访问其中的whatEver(),将它声明为静态函数并不是一个好主意,因为假设是{ {1}}指向实例化的对象。

类模型不能很好地适应javascript,而且混淆通常源于此。

我想再补充一点:

this

事实并非如此。 Javascript中的所有函数都是共享的,this// so, the following will be shared, and this // is the best practice, right?: Person.prototype.whatEver = function(){ return this.firstName + " " + this.lastName; } 只是声明函数的两种不同方式。

可以使用Person.prototype.whatEver创建的对象调用

Person.whatEver,这是一个构造函数调用。我的意思是当使用Person.prototype.whatEver调用函数时,会创建一个空对象,new Person(..)绑定到这个新对象,并且对象获得new - 链接到{{1} }。

因此,当您将其this实例化,并调用prototype时,它会尝试在原型链中找到Person函数引用,并会找到var p = new Person(..)中有一个被调用。