繁体   English   中英

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

[英]ES6 static method vs non-static and ES5 OOP

我有点困惑。

如果,例如...:

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

就是这样,对吗?:

// it would need to be inside of the class, of course
static whatEver(){
    return this.firstName + " " + this.lastName;
}

虽然这相当于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'];
  }
  // ...

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

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

所以如果你有像这样的代码:

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

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

//contstructor 
function Person () { … } 

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

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

所有函数定义仅在Memory中创建一次。 差异是»这个背景«:

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 () {}

}

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

这来自于对Javascript中函数如何工作的误解。

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

Javascript不是基于class的。

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

Java或C ++中的static方法不需要实例化,这可能非常有用。

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

在你的代码中

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()函数,如果你需要访问this它,这不是一个好主意,声明为静态函数,因为假设的是, this指向实例化的对象。

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


我想补充一点:

// so, the following will be shared, and this 
// is the best practice, right?:
Person.prototype.whatEver = function(){
    return this.firstName + " " + this.lastName;
}

这不是真的。 Javascript中的所有函数都是共享的, Person.prototype.whatEverPerson.whatEver只是两种不同的声明函数的方式。

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

所以当你像var p = new Person(..)一样实例化它,并调用p.whatEver() ,它会尝试在原型链中找到whatEver(..)函数引用 ,并在Person.prototype找到一个,被调用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM