JavaScript模块模式 - 使用"return this"有什么好处?

14

在了解了模块模式之后,我看到有几种返回想要公开的属性的方法。

其中最常见的一种是在"return"语句内声明您的公共属性和方法,与您的私有属性和方法分离。类似的方式(“揭示”模式)是仅提供对您希望公开的属性和方法的引用。最后,我看到的第三种技术是在您的模块函数内创建一个新对象,将您的新属性分配给该对象,然后返回该对象。这是一个有趣的想法,但需要创建一个新对象。

所以我在想,为什么不只使用this.propertyName来分配您的公共属性和方法,最后在结尾处使用return this?这种方式对我来说似乎更简单,因为您可以使用通常的varfunction语法创建私有属性和方法,或者使用this.propertyName语法声明您的公共方法。

以下是我建议的方法:

(function() {

var privateMethod = function () {
    alert('This is a private method.');
}

this.publicMethod = function () {
    alert('This is a public method.');
}

return this;

})();

使用上述方法有哪些优缺点?其他方法呢?


5
你有没有考虑过“this”到底是什么?你在哪里添加你的publicMethod? - Jakob Kruse
5个回答

30

你的函数没有对象上下文,因此在这种情况下,this 引用全局的 window 对象。每个分配给 this 的属性都会自动污染全局命名空间。

(function() {
    console.log(this == window); // true

    this.publicMethod = function () {
        alert('This is a public method.');
    }

})();

console.log(publicMethod); // function()

您可以明确地传递一个对象来告诉它使用哪个上下文。

var MYAPP = {};

(function() {
    // 'this' will now refer to 'MYAPP'
    this.publicMethod = function () {
        alert('This is a public method.');
    }
}).call(MYAPP);

console.log(publicMethod); // undefined
console.log(MYAPP.publichMethod); // function()

你可以用其他风格来编写:

var MYAPP = (function(my) {
    var my;
    ⋮
    return my;
})(MYAPP);

我们到达了一个已经讨论过的模式。有关详细信息,请参阅达斯汀在匿名函数作用域上的文章。


非常感谢。我之前不知道匿名函数中“this”的行为。 - Rob Gibbons
这与函数是否是匿名函数无关,而与如何调用函数有关(任何函数都可能是通过函数声明或函数表达式创建的)。如果您使用表达式 f() 调用存储在变量 f 中的函数(例如通过函数声明 function f() {} 或通过分配给变量的函数表达式 var f = function() {}; 定义的),则 this 总是全局对象。 - Tim Down

4
我建议您采用以下方式,将公共属性和方法添加到匿名对象中,然后返回该对象:

我建议您采用以下方式,将公共属性和方法添加到匿名对象中,然后返回该对象:

var myModule = (function() {
    function privateMethod() { ... }
    function publicMethod() { ... }

    return { publicMethod: publicMethod };
})();

好的,是的,除非你返回的东西立即被丢弃。 - Jason S
我很好奇Jason的意思是什么。使用匿名对象作为返回值会出现什么问题?当使用模块模式时,这似乎是我遇到的最佳技术之一。 - Rob Gibbons
我认为Jason指的是被省略或推断的代码,因为我们正在讨论模块模式。我会更新我的示例。 - Jakob Kruse

2

如果您想发布方法,可以执行以下操作:

var export = (function() {

var privateMethod = function () {
  alert('This is a private method.');
}
var export = {};

export.publicMethod = function () {
  alert('This is a public method.');
}

return export;

})();

2

另一个选择是完全避免this引用。定义一个函数来创建并返回一个匿名对象。

function makeThing(someAttribute) {
  var privateVariable = 42;

  function someMethod() {
    return privateVariable;
  }

  return {
    "publicMethodName": someMethod,
    "getAttribute": function() {
      return someAttribute;
    }
  };
}

var thing = makeThing(99);
thing.publicMethodName();
thing.getAttribute();

1
揭示模块模式:
var m1 = (function(){ return {method: mthod} })();
var m2 = new function Singleton(){ return {method: mthod} };
var m3 = ({}).prototype = {method: method};
var m4 = ({}).prototype = (function(){ ... })();
var m5 = (function(){}).prototype = {} || (function(){ ... })();

var m6 = (function(extendee){
    return extendee.prototype = {attr3: 'attr3'};
})({currentAttr1: 1, currentAttr2: 2});

另外,如果您需要方法链:
var m = (function(){}).prototype = (function(){
    var thus = m;  // this
    console.log('m this-------', thus);

    function fn(){
        console.log('fn', thus);
        return thus;
    }
    function f(){
        console.log('f', thus);
        return 'poop';
    }

    return {f: f, fn: fn};
})();

console.log('M:', m, 'm.fn', m.fn(), 'm.fn.f', m.fn().f());

此外还有很多其他的方法,你也可以将你的模块作为主角。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接