Javascript 通过原型对象或构造函数设置方法,有什么区别?

Javascript 通过原型对象或构造函数设置方法,有什么区别?,javascript,constructor,prototype,Javascript,Constructor,Prototype,你能解释一下构造函数和原型对象中设置方法的区别吗?下面的代码显示了这两种设置方法的方法-say_hello和say_bye都可以正常工作: function MessageClass() { this.say_bye = function() { alert('see ya'); }; } MessageClass.prototype.say_hello = function() { alert('hello'); }; x = new MessageClass(); x.say_hel

你能解释一下构造函数和原型对象中设置方法的区别吗?下面的代码显示了这两种设置方法的方法-say_hello和say_bye都可以正常工作:

function MessageClass() {
  this.say_bye = function() { alert('see ya'); };
}

MessageClass.prototype.say_hello = function() { alert('hello'); };

x = new MessageClass();
x.say_hello();
x.say_bye();

区别在于从消息类派生类时。只有在原型上声明的方法才能在消息的子类上使用。

如果通过原型绑定方法,JS只需执行一次,并绑定到一个对象类,该对象类使得OO JS扩展可以省略


如果您在类函数中进行绑定,JS必须为每个实例进行创建和分配。

foxxtrot和annakata都是正确的,但我会投入2美分

如果使用原型,那么MessageClass的每个实例实际上都引用相同的函数。这些函数只存在于内存中一次,并用于所有实例。如果在构造函数中声明方法,或者将其添加到特定实例而不是原型中,则会为MessageClass的每个实例创建一个新函数

也就是说,在大多数情况下,可能没有任何明显的性能差异,您也不太可能看到内存使用的差异。我会选择原型方法,除非你有令人信服的理由不这样做。我可以告诉您,您可能希望在构造函数中声明方法的唯一原因是您是否需要闭包。例如,如果您有事件处理程序,或者希望使用getter/setter模拟私有属性,则可以执行以下操作:

function MessageClass() {
    var self = this;
    this.clickHander = function(e) { self.someoneClickedMe = true; };

    var _private = 0;
    this.getPrivate = function() { return _private; };
    this.setPrivate = function(val) { _private = val; };
}
编辑:因为已经讨论过这如何影响由另一个对象扩展的对象以及构造函数中分配的函数,所以我添加了更多的细节。我可能会使用类这个术语来简化讨论,但需要注意的是,js不支持类,这并不意味着我们不能进行良好的OO开发,或者我们不会讨论这个问题

大多数javascript库调用基类和子类上的构造函数。e、 js的Object.extend这意味着在每个对象的构造函数中分配的方法将在生成的对象上可用。但是,如果您自己扩展对象,可能会产生意想不到的后果

如果我接受上面的MessageClass并扩展它:

function ErrorMessageClass() {}
ErrorMessageClass.prototype = new MessageClass();

errorMsg = new ErrorMessageClass();
然后errorMsg将有一个getPrivate和setPrivate方法,但它们的行为可能与您预期的不同。因为这些函数在分配时被限定了作用域,即在ErrorMessageClass.prototype=new MessageClass,不仅get/setPrivate方法是共享的,而且_private变量也在ErrorMessageClass的所有实例中共享。这本质上使_private成为ErrorMessageClass的静态属性。例如:

var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'A'
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'B'
与clickHandler函数和someoneClickedMe属性类似:

errorA.clickHandler();
console.log(errorA.someoneClickedMe); // prints 'true'
console.log(errorB.someoneClickedMe); // prints 'true'
但是,请更改这些函数定义以使用此函数。\u private:

this.getPrivate = function() { return this._private; };
this.setPrivate = function(val) { this._private = val; };
ErrorMessageClass实例的行为也变得更符合您的预期:

errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate()); // prints 'A'
console.log(errorB.getPrivate()); // prints 'B'

因此,如果我有'BetterMessageClass.prototype=new MessageClass',只会继承'say_hello'。我能够从子类调用声明为此的say_bye方法。这是我的代码:函数Employee{this.say_bye=function{alert'see ya';};}函数Manager{}Manager.prototype=new Employee;Manager.prototype.constructor=Manager;var经理=新经理;经理,说再见@这是不对的。甚至在这个内部构造函数上声明的方法也可以在子类中访问。由PrestAube考虑代码ErrOR.StPrimaTya',它访问父类MessageClass声明的方法。我也错误地认为差异在继承中,但它不:函数PARTRONTROPE类{SIT.EnITEDFUNC=函数{返回一些值};}函数CytCype {};childClass.prototype=新父类;var childObj=新的子类;console.logchildObj.inheritedFunc//成功地记录了一些值如果我先将方法定义为函数,然后在构造函数中说:“this.say\u bye=MessageClass\u sayhello;稍微好一点,但仍然不如原型设计那么有效,而且您仍然无法扩展。能否扩展对象在很大程度上取决于您使用的js库以及是否使用js库。如果在扩展对象时调用构造函数,则方法可用。我相信大多数主要的库在扩展时都会调用构造函数;然后,在类构造函数中分配的函数在子类上可用。但是,这些函数是在子类的实例之间共享的,这可能会导致意外的行为。当然最好是做个原型。见鬼,你的口才:虽然我不同意你的观点,但我
没有明显的区别,尽管您确实使用了它。\u private,该变量可以从外部访问。从技术上讲,在大多数(如果不是全部)JS环境中,您都可以使用调试器进行跟踪