Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/372.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
有没有办法利用在JavaScript工厂函数中使用原型方法的性能优势?_Javascript_Performance_Prototype_Factory_Factory Pattern - Fatal编程技术网

有没有办法利用在JavaScript工厂函数中使用原型方法的性能优势?

有没有办法利用在JavaScript工厂函数中使用原型方法的性能优势?,javascript,performance,prototype,factory,factory-pattern,Javascript,Performance,Prototype,Factory,Factory Pattern,我正在寻找以类似于Java类的方式编写面向对象JavaScript(JS)代码的最佳方法 工厂函数(FFs)看起来是在JS中提供类功能的一种非常有前途的方法,到目前为止,我一直在这样构建它们: function FF(constructorArg) { var _privateName = constructorArg; var publicMessage = "Hello StackOverflow"; function publicMethodGetName() {

我正在寻找以类似于Java类的方式编写面向对象JavaScript(JS)代码的最佳方法

工厂函数(FFs)看起来是在JS中提供类功能的一种非常有前途的方法,到目前为止,我一直在这样构建它们:

function FF(constructorArg)
{
   var _privateName = constructorArg;

   var publicMessage = "Hello StackOverflow";

   function publicMethodGetName() {
      return _privateName;
   }

   return {
      publicMethodGetName: publicMethodGetName,
      publicMessage: publicMessage
   };
}
// constructor and factory function definition
function MyCntr(initialCnt) {
    if (!(this instanceof MyCntr)) {
        return new MyCntr(initialCnt);
    } else {
        // initialize properties
        this.cntr = initialCnt || 0;
    }
}

MyObject.prototype = {
    getCntr: function() {
        return this.cntr++;
    },
    resetCntr: function() {
        this.cntr = 0;
    }
};
var m = new MyCntr(10);
console.log(m.getCntr());    // 10
然而

在中的第二个答案中,Eric Elliot谈到了自由流:

如果您将原型存储在父对象上,这可能是一种很好的方法 动态交换功能,并实现非常灵活的 对象实例化的多态性

我在网上找不到任何这样的例子。有人能解释一下我如何使用上面的FF来实现这一点吗

如果我知道许多对象将从同一个FF创建,这是否意味着我可以将该FF转换为使用原型方法

我正在寻找编写面向对象JavaScript(JS)的最佳方法 以类似于Java类的方式编写代码

这是你的第一个错误。Javascript是一种非常不同的语言,您不应该试图在Javascript中模仿其他语言。当我来自C++时,我做了一些类似的事情,这是个大错误。相反,您需要做的是学习Javascript的优势,以及在使用Javascript编写时如何以“Javascript方式”最好地解决问题。我知道这是一种很自然的倾向,用你在其他语言中已经知道的方式做事,但这是一个错误。因此,不要试图用“Java方式”做事,而是问问Javascript中解决某些特定问题的最佳方式是什么

例如,在大量对象上使用方法的内存最低的方法是使用Javascript的原型。您可以将原型与手动分配给原型一起使用,也可以与较新的ES6
class
语法一起使用。这两种方法都在原型对象上创建方法,然后在所有实例之间高效地共享

例如,您可以将factory函数与以下典型原型一起使用:

function FF(constructorArg)
{
   var _privateName = constructorArg;

   var publicMessage = "Hello StackOverflow";

   function publicMethodGetName() {
      return _privateName;
   }

   return {
      publicMethodGetName: publicMethodGetName,
      publicMessage: publicMessage
   };
}
// constructor and factory function definition
function MyCntr(initialCnt) {
    if (!(this instanceof MyCntr)) {
        return new MyCntr(initialCnt);
    } else {
        // initialize properties
        this.cntr = initialCnt || 0;
    }
}

MyObject.prototype = {
    getCntr: function() {
        return this.cntr++;
    },
    resetCntr: function() {
        this.cntr = 0;
    }
};
var m = new MyCntr(10);
console.log(m.getCntr());    // 10
然后,您可以使用传统的
new
操作符创建对象,如下所示:

function FF(constructorArg)
{
   var _privateName = constructorArg;

   var publicMessage = "Hello StackOverflow";

   function publicMethodGetName() {
      return _privateName;
   }

   return {
      publicMethodGetName: publicMethodGetName,
      publicMessage: publicMessage
   };
}
// constructor and factory function definition
function MyCntr(initialCnt) {
    if (!(this instanceof MyCntr)) {
        return new MyCntr(initialCnt);
    } else {
        // initialize properties
        this.cntr = initialCnt || 0;
    }
}

MyObject.prototype = {
    getCntr: function() {
        return this.cntr++;
    },
    resetCntr: function() {
        this.cntr = 0;
    }
};
var m = new MyCntr(10);
console.log(m.getCntr());    // 10
或者,您可以将其用作出厂功能:

var m = MyCntr(10);
console.log(m.getCntr());    // 10
var m = MyCntr(10);
console.log(m.getCntr());    // 10

请记住,对于ES6(或transpiler),您也可以使用ES6类语法:

class MyCntr {
    constructor(initialCnt) {
        if (!(this instanceof MyCntr)) {
            return new MyCntr(initialCnt);
        } else {
            // initialize properties
            this.cntr = initialCnt || 0;
        }
    }

    getCntr() {
        return this.cntr++;
    }

    resetCntr() {
        this.cntr = 0;
    } 
}

var m = new MyCntr(10);
console.log(m.getCntr());    // 10
或者,您可以将其用作出厂功能:

var m = MyCntr(10);
console.log(m.getCntr());    // 10
var m = MyCntr(10);
console.log(m.getCntr());    // 10
这两种语法创建了完全相同的对象定义和原型


尽管如此,不使用原型的内存消耗通常不是什么大问题,除非你有很多方法和很多对象,并且不使用原型有一些显著的优势。一个大问题是,您可以在构造函数创建的闭包中拥有真正私有的实例数据。这里是前面同样的示例,其中
cntr
实例变量是真正私有的

// constructor and factory function definition
function MyCntr(initialCnt) {
    // truly private instance variable
    var cntr;

    if (!(this instanceof MyCntr)) {
        return new MyCntr(initialCnt);
    } else {
        // initialize properties
        cntr = initialCnt || 0;
    }

    this.getCntr = function() {
        return cntr++;
    }

    this.resetCntr = function() {
        cntr = 0;
    }
}
这确实使用了更多内存,因为构造函数函数(包含
cntr
变量)创建了一个持久的闭包,并且组成方法的每个函数都有新的实例。但是,这在记忆上并没有太大的区别。如果没有数以百万计的cntr对象,内存消耗差异可能无关紧要。DougCrawford是这种Javascript编码风格的拥护者之一。你可以在这里看到他早期关于这个主题的一篇文章:这里讨论了克罗克福德的一些观点。在某处有一个Crockford视频(我现在找不到),他在那里为非原型风格辩护


因此,问你是否能将两者结合起来是合乎逻辑的。不,不是真的。为了访问构造函数闭包,必须在构造函数的词法范围内定义这些方法,并且要做到这一点,它们不在原型上。试图将它们分配给构造函数内的原型会造成混乱,容易受到各种错误的影响,因此也不可行

使用ES6
weakMap
对象,可以在使用原型时生成私有实例数据,尽管我想说的是,它通常更麻烦,因为它只会使编写代码和访问私有数据变得复杂,但这是可能的。您可以在和中使用
weakMap
查看私有变量的实现


我的观点是,通过某种方式消除对
new
的需求来隐藏您正在创建一个新对象的事实并不是非常像Javascript或者非常像OO。在创建新对象和调用函数时,阅读代码的人应该很清楚这一点。使用一个大写的构造函数,使用<代码>新< /COD>使JavaScript非常明显,我认为这是一件好事。我不会故意在代码中避免这种明显的意图


如果您将原型存储在父对象上,这可能是一种很好的方法 动态交换功能,并实现非常灵活的 对象实例化的多态性

如果您使用原型,它确实是一个很好的封装对象,包含了对象的所有方法,并且它可以使一些事情变得更容易。但是,如果不使用原型,也可以执行多态性

例如,假设您有三个不使用原型的对象,并且它们在其构造函数中分配了所有方法,并且您希望创建这三个对象的mixin组合

您可以创建一个对象,然后只调用其他构造函数,它们将自动将您的对象初始化为具有所有三种行为的组合对象(假设实例数据属性或方法名称中没有冲突)

这将调用三个构造函数中的每一个,它们将分别初始化其方法和实例变量。在某些方面,这比使用原型更简单

如果