簡體   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