Javascript 将原型函数绑定到此函数的不太详细的方式

Javascript 将原型函数绑定到此函数的不太详细的方式,javascript,refactoring,prototype,Javascript,Refactoring,Prototype,我使用以下声明类的范例: var myNamespace = myNamespace || {}; (function () { myNamespace.MyClass = function () { if (!(this instanceof myNamespace.MyClass)) { return new myNamespace.MyClass(); } this.field = 17;

我使用以下声明类的范例:

var myNamespace = myNamespace || {};
(function () {
    myNamespace.MyClass = function () {
        if (!(this instanceof myNamespace.MyClass)) {
            return new myNamespace.MyClass();
        }

        this.field = 17;

        this.foo = this.foo.bind(this);
        this.bar = this.bar.bind(this);
    };

    myNamespace.MyClass.prototype.foo = function(){
        console.log(this.field + 1);
    };

    myNamespace.MyClass.prototype.bar = function(){
        console.log(this.field + 2);
    };
})();
我使用
prototype
来避免在每次实例化时重新说明对象方法,并使代码更干净—将类字段与其逻辑分离。
我在每个方法上调用
bind
,以避免在
这个
指向方法内部错误的地方出现讨厌的bug

它可以工作,但很容易出错——我必须记住对每个方法调用
bind
,而且太冗长了,特别是当有两个以上的方法时

是否有更干净的*方法来声明此类函数(绑定到其类型的
this
,并在
原型上声明)?


*我知道“clean”并没有很好的定义——一个简单的度量就是代码长度

声明类后附加到命名空间:

var myNamespace = myNamespace || {};
(function () {
    var MyClass = function () {
        this.field = 17;
    };

    MyClass.prototype.foo = function(){
        console.log(this.field + 1);
    };

    MyClass.prototype.bar = function(){
        console.log(this.field + 2);
    };
    this.MyClass = MyClass;

}).call(myNamespace);

通过以命名空间作为作用域调用IIFE,您可以通过在
this
对象上公开类来保持模块干净。

声明类后附加到命名空间:

var myNamespace = myNamespace || {};
(function () {
    var MyClass = function () {
        this.field = 17;
    };

    MyClass.prototype.foo = function(){
        console.log(this.field + 1);
    };

    MyClass.prototype.bar = function(){
        console.log(this.field + 2);
    };
    this.MyClass = MyClass;

}).call(myNamespace);

通过使用名称空间作为作用域调用IIFE,您可以通过在
this
对象上公开类来保持模块的干净。

您不应该像那样绑定您的方法-您在每个实例上创建新函数,而您实际上应该在原型上使用方法来节省内存。如果您创建100个实例,您将创建200个新函数!这样一种简单的模式更为常见,可以很好地工作:

var myNamespace = myNamespace || {};
myNamespace.MyClass = (function() {
  function MyClass() {
    this.field = 17;
  }

  MyClass.prototype = {
    constructor: MyClass,
    foo: function() {
      console.log(this.field + 1);
    },
    bar: function(){
      console.log(this.field + 2);
    }
  };

  return MyClass;
}());

你不应该像那样绑定你的方法——你在每个实例上创建新的函数,而实际上你应该在原型上使用这些方法来节省内存。如果您创建100个实例,您将创建200个新函数!这样一种简单的模式更为常见,可以很好地工作:

var myNamespace = myNamespace || {};
myNamespace.MyClass = (function() {
  function MyClass() {
    this.field = 17;
  }

  MyClass.prototype = {
    constructor: MyClass,
    foo: function() {
      console.log(this.field + 1);
    },
    bar: function(){
      console.log(this.field + 2);
    }
  };

  return MyClass;
}());

您可以在单个赋值中压缩一些原型定义,并将名称空间传递到函数调用中

var myNamespace = myNamespace || {};
(function () {
    function MyClass() { 
        this.field = 17;
    };

    MyClass.prototype = {
        foo: function () {
            console.log(this.field + 1);
        },

        bar: function () {
            console.log(this.field + 2);
        }
    };
})(myNamespace);

您可以在单个赋值中压缩一些原型定义,并将名称空间传递到函数调用中

var myNamespace = myNamespace || {};
(function () {
    function MyClass() { 
        this.field = 17;
    };

    MyClass.prototype = {
        foo: function () {
            console.log(this.field + 1);
        },

        bar: function () {
            console.log(this.field + 2);
        }
    };
})(myNamespace);

当您有完全可重用的泛型方法时,绑定是不好的。你可以给函数起一个名字来避免“prototype”。在任何地方,只要将构造函数发布到你的命名空间,并在包装器中使用本地路径就可以了。“我在每个方法上调用bind,以避免讨厌的bug”,这是非常过分的。理解JavaScript的工作原理并有意避免这些错误,比试图“修复”语言、避免整个过程中的一整套功能要好得多。这些讨厌的错误经常发生,特别是如果你像我一样使用knockoutjs。考虑一下所描述的内容。当你的方法用另一个上下文调用时,你应该小心和有见识。最好的解决方案不是在每个实例上都有绑定方法。如果有完全可重用的泛型方法,绑定就不好。你可以给函数起一个名字来避免“prototype”。在任何地方,只要将构造函数发布到你的命名空间,并在包装器中使用本地路径就可以了。“我在每个方法上调用bind,以避免讨厌的bug”,这是非常过分的。理解JavaScript的工作原理并有意避免这些错误,比试图“修复”语言、避免整个过程中的一整套功能要好得多。这些讨厌的错误经常发生,特别是如果你像我一样使用knockoutjs。考虑一下所描述的内容。当你的方法用另一个上下文调用时,你应该小心和有见识。最好的解决方案不是在每个实例上都有绑定方法。假设在其他地方,我实例化:
var asdf=new myNamespace.MyClass()
,然后将
asdf.foo
传递给:
window.addEventListener(“DOMContentLoaded”,asdf.foo)
,这会指向
asdf
?如果不调用
bind
,它将如何工作?当您添加事件侦听器时,无论您希望它维护什么范围(或使用匿名函数),您都会调用bind。创建函数时不绑定。假设在其他地方,我实例化:
var asdf=new myNamespace.MyClass()
,然后将
asdf.foo
传递给:
window.addEventListener(“DOMContentLoaded”,asdf.foo)
,这一点会在
asdf
吗?如果不调用
bind
,它将如何工作?当您添加事件侦听器时,无论您希望它维护什么范围(或使用匿名函数),您都会调用bind。创建函数时没有绑定。请看我在@Jivings的回答中问的问题-此解决方案是否会丢失与实例的绑定?是的,这就是问题所在,您不想这样做。就像我说的,bind创建了一个新函数,所以你在每个实例上创建了两个新函数,它们必须存储在内存中。这是一种低效的、糟糕的做法——事实上,它完全绕过了使用原型的目的。只需使用window.addEventListener(“DOMContentLoaded”,function(){asdf.foo();})。如果您经常这样做,那么将其抽象为一个helper函数。绑定并不意味着是一种可以在每个类方法上使用的通用工具。请看我在@Jivings的回答中提出的问题-这个解决方案是否会丢失对实例的绑定?是的,这就是问题所在,您不想这样做。就像我说的,bind创建了一个新函数,所以你在每个实例上创建了两个新函数,它们必须存储在内存中。这是一种低效的、糟糕的做法——事实上,它完全绕过了使用原型的目的。只需使用window.addEventListener(“DOMContentLoaded”,function(){asdf.foo();})。如果您经常这样做,那么将其抽象为一个helper函数。绑定并不意味着它是一种可以在每个类方法上使用的通用工具。