我们是否仍然需要ES6中的原型才能在所有类实例中共享一个方法副本?

kon*_*dos 6 javascript ecmascript-6

更新2:这个问题很乱,因为我认为ES6 class不会修改.protototype,它确实如此,因此这正是我想要的.

我接受了最广泛的答案,即使所有的答案和评论都应该指出我在一开始就正确的方向:)

谢谢你们!

旧:

在旧的JS,ES6之前,当我们学习制作"类"时:

function X() {
    this.foo = function(){
    }
}; 
var x = new X();
Run Code Online (Sandbox Code Playgroud)

我们也知道每次我们都会x = new X();得到'foo'方法的副本,在每个实例中这都是使用原型的一个好主意的原因之一.

现在,在ES6中我们有了这个新的酷类语法,但是具有相同的"问题",即这里复制了'f'方法.我们如何以ES6方式避免它?或者我们还需要使用.prototype吗?

class X{
  f(){
    return 'f';
  }
}

console.clear();
let x1 = new X();
let x2 = new X();
x2.f = function() {return 'changed f';};

console.log(x1.f());//f
console.log(x2.f());//changed f
Run Code Online (Sandbox Code Playgroud)

更新

我知道我们仍然可以使用.prototype.我的问题是了解如何使用更现代的方式来实现我想要的东西,即具有复制的方法.我检查了关于JS原型的第一个教程,如果我的英语很差,请查找引文:) - 在https://hackernoon.com/prototypes-in-javascript-5bba2990e04b上找到:

(...)即使用构造函数创建的每个对象都将拥有自己的属性和方法副本.有两个函数fullName实例做同样的事情是没有意义的.为每个对象存储单独的函数实例会导致内存浪费.我们将看到我们如何解决这个问题.

你还提到这class ...只是一个语法糖,但是为什么......下面的函数FC,我们可以看到直接在fc1中看到"f"方法,并且

function FC() {
    this.v = 42;
    this.f = function(){
    }
}; 

var fc1 = new FC();

console.log('fc1, we can see the "f" directly in fc1: ', 
    Object.getOwnPropertyNames(fc1)
);


//////////////////////////////////

class X{
  constructor(){
    this.v  = 'bar';
  }
  f(){
    return 'f';
  }
}


let x1 = new X();

console.log('x1, we don\'t, because we have it in prototype:',
    Object.getOwnPropertyNames(x1)
);
Run Code Online (Sandbox Code Playgroud)

Car*_*uis 6

ECMAScript 2015中引入的JavaScript类主要是基于JavaScript现有基于原型的继承的语法糖.类语法没有向JavaScript引入新的面向对象的继承模型.

阅读有关MDN的更多信息

您的代码摘录转换为,如下所示:

function X() { }

X.prototype.f = function f() {
  return 'f';
};

let x1 = new X();

let x2 = new X();
x2.f = function() { return 'changed f'; };

console.log(x1.f()); // f
console.log(x2.f()); // changed f
Run Code Online (Sandbox Code Playgroud)

请注意,输出保持不变.

您可以使用Babel repl并检查已编译的代码.


Est*_*ask 5

ES6类是已在ES5中使用的已建立继承模式的语法糖.

ES6类通过设计使用原型方法.一个方法在实例之间共享,因此在prototype对象上定义一次并在实例中原型继承它是合理的.原型在现代发动机中始终如一地优化,并且在某些情况下显示出性能优势,因此在适当的情况下它们可以是首选.

我的问题更多的是使用更现代的方式来实现我想要的,即没有方法的副本.

通过重用功能可以减少内存占用.这不是一种"现代"方式,只是解决问题的一种方法:

function function f(){}
function FC() {
    this.v = 42;
    this.f = f;
};
Run Code Online (Sandbox Code Playgroud)

"现代"方式是使用原型成员.

FC函数不是X类的直接对应函数,因为前者f在实例上赋值,而不是构造函数原型.直接对应物(f描述符除外,它在ES6类中也是不可枚举的)将是:

function FC() {
    this.v = 42;
}; 
FC.prototype.f = function(){};

class X{
  constructor(){
    this.v  = 'bar';
  }
  f(){}
}
// typeof X.prototype.f === 'function'
Run Code Online (Sandbox Code Playgroud)

这种风格在ES5中没有得到一致使用的原因是因为this.f输入的字符数量较少而且可读性较高FC.prototype.f,而开发人员可能不知道它的好处和怪癖prototype.

原型成员(方法和getter/setter)的推广是class语法糖解决的几个问题之一.