繁体   English   中英

如何在JavaScript模块模式中的私有函数中调用公共函数

[英]How do I call a public function from within a private function in the JavaScript Module Pattern

如何在JavaScript模块模式的私有函数中调用公共函数?

例如,在以下代码中,

var myModule = (function() {
    var private1 = function(){
        // How to call public1() here?
        // this.public1() won't work
    }

    return {
        public1: function(){ /* do something */}
    }
})();

这个问题之前曾被问过两次 ,但每个问题的答案都不同。

  1. 在返回对象之前,请保存对它的引用,然后使用该引用访问public方法。 答案
  2. 在闭包中保存对public方法的引用,并使用该引用访问public方法。 答案

虽然这些解决方案有效,但从OOP的角度来看,它们并不令人满意。 为了说明我的意思,让我们对每种解决方案分别进行一个雪人的具体实现,并将其与简单的对象文字进行比较。

雪人1:保存对返回对象的引用

var snowman1 = (function(){
  var _sayHello = function(){
    console.log("Hello, my name is " + public.name());
  };

  var public = {
    name: function(){ return "Olaf"},
    greet: function(){
      _sayHello();
    }
  };
  return public;
})()

雪人2:保存对公共功能的引用

var snowman2 = (function(){
  var _sayHello = function(){
    console.log("Hello, my name is " + name());
  };
  var name = function(){ return "Olaf"};

  var public = {
    name: name,
    greet: function(){
      _sayHello();
    }
  };
  return public;
})()

雪人3:物件文字

var snowman3 = {
    name: function(){ return "Olaf"},
    greet: function(){
      console.log("Hello, my name is " + this.name());
    }
}

我们可以看到这三个函数在功能上相同,并且具有完全相同的公共方法。

但是,如果我们测试简单覆盖

var snowman = // snowman1, snowman2, or snowman3
snowman.name = function(){ return "Frosty";}
snowman.greet(); // Expecting "Hello, my name is Frosty"
                 // but snowman2 says "Hello, my name is Olaf"

我们看到#2失败了。

如果我们进行原型覆盖测试,

var snowman = {};
snowman.__proto__ = // snowman1, snowman2, or snowman3
snowman.name = function(){ return "Frosty";}
snowman.greet(); // Expecting "Hello, my name is Frosty"
                 // but #1 and #2 both reply "Hello, my name is Olaf"

我们看到#1和#2都失败了。

这是一个非常丑陋的情况。 仅仅因为我选择了以一种或另一种方式重构代码,返回对象的用户就必须仔细研究我如何实现一切以弄清楚他/她是否可以覆盖我的对象的方法并期望它能工作! 尽管此处的观点有所不同,但我个人的观点是正确的覆盖行为是简单对象文字的行为。

因此,这才是真正的问题:

有没有一种方法可以从私有方法中调用公共方法,以使生成的对象在覆盖行为方面像对象文字一样工作?

你可以用this来让你的特权方法的对象greet被称为上。

然后,您可以将该值传递给您的私有方法_sayHello ,例如,使用callapply或作为参数:

var snowman4 = (function() {
    var _sayHello = function() {
        console.log("Hello, my name is " + this.name);
    };
    return {
        name: "Olaf",
        greet: function() {
            _sayHello.call(this);
        }
    };
})();

现在你可以做

var snowman = Object.create(snowman4);
snowman.greet(); // "Hello, my name is Olaf"
snowman.name = "Frosty";
snowman.greet(); // "Hello, my name is Frosty"

并且

snowman4.greet(); // "Hello, my name is Olaf"
snowman4.name = "Frosty";
snowman4.greet(); // "Hello, my name is Frosty"

使用模块模式,您可以将对象的所有先天都隐藏在局部变量/函数中,并且通常在公共函数中使用它们。 每次使用模块模式创建新对象时,也会创建一组新的公开函数-具有自己的作用域状态。

使用原型模式,您可以使用同一组方法来处理某种类型的所有对象。 这些方法的变化是this对象-换句话说,就是它们的状态。 但是, this是从来没有隐藏。

不用说,很难将它们混合在一起。 一种可能的方法是使用Object.create使用的方法提取到模块生成的对象的原型中。 例如:

var guardian = function() {
    var proto = {
        greet: function () {
            console.log('I am ' + this.name());
        },
        name: function() {
            return 'Groot';
        }
    };
    var public = Object.create(proto);
    public.argue = function() {
        privateGreeting();
    };

    var privateGreeting = public.greet.bind(public);
    return public;
};

var guardian1 = guardian();
guardian1.argue(); // I am Groot
var guardian2 = guardian();
guardian2.name = function() {
  return 'Rocket';
};
guardian2.argue(); // I am Rocket
var guardian3 = guardian();
guardian3.__proto__.name = function() {
  return 'Star-Lord';
};
guardian3.argue(); // I am Star-Lord

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM