鍍金池/ 問答/C++  Linux  HTML/ 如何解決js面向對象開發(fā)中的命名空間沖突

如何解決js面向對象開發(fā)中的命名空間沖突

背景

  1. 目的是開發(fā)一套圖表庫,供外部使用
  2. 使用js自定義“類”,并有繼承關系
  3. 在使用這些自定義“類”的時候,有命名沖突的問題
  4. 使用該圖表庫的時候,無法保證庫中的變量不和外部產生命名沖突

問題描述
如下圖所示,

  1. dog,cat擁有相同“類包”(class packge)結構
  2. dog,cat擁有同名的“類文件”(MyClass.js , ExtendsMyClass.js)
    ---當然它們的內容不同
  3. 要在index.html中同時使用dog,cat各個類的實例
  4. 問題1來了: 命名沖突
  5. 問題2來了: 無法避免index.html中其他js腳本和圖表庫產生命名沖突

圖片描述



想到的可能的解決方案
<一>
將所有類的名字特異唯一化。
比如:
doc --- action --- MyClass.js / ExtendsMyClass.js
cat --- action --- MyClass1.js / ExtendsMyClass1.js
pig --- ...
mouse --- ...
...

這是“超級XX”的方法,不予理會!

<二>
模塊化,不是有AMD,CMD嘛?
抱歉,沒接觸過。
收集資料,看了,沒有理解透。
能否解決我的問題,需要朋友們指點。

<三>
把dog結構下所有“類”文件的內容都定義在一個文件中,且用
var moduleDog = new Object{ ... dog的全部內容 ... }
包裹起來。

cat也是如此。
這種“模塊化”在有“類繼承”的本例中是否可行?需要朋友們指點。

<四>
其他方案未知,需要朋友們指點。

代碼
cat的 MyClass.js

function MyAction()
{
    this.name = 'cat' ;
}

cat的 ExtendsMyClass.js

function ExtendsMyAction()
{
    this.name = 'extends cat' ;
}

ExtendsMyAction.prototype = new MyAction() ;
ExtendsMyAction.prototype.constructor = ExtendsMyAction ;

dog的 MyClass.js

function MyAction()
{
    this.name = 'dog' ;
}

dog的 ExtendsMyClass.js

function ExtendsMyAction()
{
    this.name = 'extends dog' ;
}

ExtendsMyAction.prototype = new MyAction() ;
ExtendsMyAction.prototype.constructor = ExtendsMyAction ;
回答
編輯回答
苦妄

TypeScript

ES6 的超集,支持async、Promiseyield等新語法


適合面向對象的場景

最終會編譯成 es5js 代碼,也就是任何瀏覽器可以執(zhí)行的JS

使用編輯器 Visual Studio Code 無縫編輯,編譯也只要運行 tsc 即可輸出目標js文件

我一般開啟嚴格模式,強類型模式,這樣在編寫過程中就可以知道是否有錯,避免一些低級錯誤

比如

下面例子中:

  • namespace 命名空間
  • abstract 虛類、虛函數
  • extends 繼承
  • : number 參數類型
  • : boolean 返回類型
  • x: number = 0 默認參數值
  • public x 類變量以及作用域
  • public position 類作用域
  • constructor 構造函數
  • public get getter setter

/ui/base.ts

namespace ui {

    abstract class Base {
        public x: number;
        public y: number;
        constructor(x: number = 0, y: number = 0)
        {
            this.setTo(x, y);
        }
        
        public abstract position(x: number, y: number);
    }
}

/ui/sharp.ts

namespace ui {
    class Sharp extends Base {
        public position(x: number, y: number)
        {
            this.x = x;
            this.y = y;
        }
    }
}

/ui/sharp/rect.ts

namespace ui.sharp
{

    class Rect extends ui.Sharp {
        public width: number;
        public height: number;
        
        public get empty(): boolean {
            return this.height == 0 || this.width == 0;
        }
        
        constructor(x: number = 0, y: number = 0, width: number = 0, height: number = 0)
        {
            super(x, y);
            this.width = width;
            this.height = height;
        }
    }
}

調用

調用方式 無特殊,js即可

let rect = new ui.sharp.Rect();
console.log(rect.empty); // true
2017年11月3日 21:19
編輯回答
薔薇花

requirejs或直接上es6使用webpack打包

2017年2月18日 10:02
編輯回答
陌上花

Symbol 可以嗎

2018年6月14日 14:31
編輯回答
孤星

決定采用“偽命名空間”的方式解決本問題。

理由:

  1. 項目規(guī)模不大,“偽命名空間”雖然使得局部代碼看起來啰嗦了一些,但是實施起來非常簡單,效果很好。
  2. 項目不希望引入第三方庫(增加本項目的學習曲線和周期,并帶來復雜性)
  3. 項目要考慮兼容ES5標準(不使用ES6語法)
  4. 項目希望用JS原生功能完成目標。(TypeScript最終也要轉譯為JS代碼,如果TS能夠實現需求,那么JS當然也能。通過掌握JS,可以推測TS的轉譯邏輯。作為學習,不錯。)

===========================================
“偽命名空間示例”

var myNamespace =
{

  a:{
          function func1()
          {
              ...
          } ,
      
          function func2()
          {
              ...
          }

          ...
    }

  b:{
          function func1()
          {
              ...
          } ,
      
          function func2()
          {
              ...
          }

          ...
    }

}

===========================================
個人理解(未必正確)
無論TS或ES6,都是通過語法糖的形式為原生jS做了一層包裝,最終都要轉譯為JS原生代碼。
那么,掌握原生JS解決下面問題的方法,是深入JS所必須的:

像Java,C#那樣,用面向對象的思路來設計復雜的庫(或軟件系統(tǒng))。該系統(tǒng)要能夠

  1. 從代碼文件結構上合理組織(比如Java的packge包結構)
  2. 能夠在不同的packge中包>含相同類名的js類
  3. 作為功能庫,在被引入時,不能夠與其他任何庫產生命名沖突

今后需學習的地方:
沒有TS或ES6開發(fā)的經驗,不好做判斷。但是,僅僅通過TS和ES6中對“類”,“類繼承”,“模塊化”的淺顯了解,個人感覺這些語法糖使得原本簡單的JS代碼變得復雜起來,這也是是代價。
希望有實戰(zhàn)經驗的朋友們對TS或ES6在解決本問題上做“能”或“不能”的判斷,如果能夠提供簡單示例代碼,那將非常感謝。

此問題暫時不關閉,等待有實戰(zhàn)經驗的朋友們給予指點!

2018年2月16日 18:11
編輯回答
挽歌

首先你這個例子不應該出現類名重復的情況.為什么不在構造函數中傳入參數來實例化.
記住在編寫代碼之前,先保證設計的合理性!不要試圖解決錯誤的邏輯.

還有現在是 es6 的時代,請自行學習 es6 的語法.來定義類.推薦 阮一峰 es6 入門
此外前端以進化到編譯型.請學習 webpack 來打包代碼.自行參看官方文檔.

所以我的建議是.

  1. 重構你的邏輯.不應該出現同名類,因為邏輯上來說一個類代表一類實體的抽象,復用邏輯請抽離為函數庫而不是類!
  2. 如果執(zhí)意要實現請利用 webpack + es6 進行重構.當然前提是你要懂 node.這個就靠你自己了.
2018年3月28日 22:19