鍍金池/ 問答/C++  Linux  HTML/ 如何解決js面向?qū)ο箝_發(fā)中的命名空間沖突

如何解決js面向?qū)ο箝_發(fā)中的命名空間沖突

背景

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

問題描述
如下圖所示,

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

圖片描述



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

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

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

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

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等新語法


適合面向?qū)ο蟮膱鼍?/p>

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

使用編輯器 Visual Studio Code 無縫編輯,編譯也只要運(yùn)行 tsc 即可輸出目標(biāo)js文件

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

比如

下面例子中:

  • namespace 命名空間
  • abstract 虛類、虛函數(shù)
  • extends 繼承
  • : number 參數(shù)類型
  • : boolean 返回類型
  • x: number = 0 默認(rèn)參數(shù)值
  • public x 類變量以及作用域
  • public position 類作用域
  • constructor 構(gòu)造函數(shù)
  • 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;
        }
    }
}

調(diào)用

調(diào)用方式 無特殊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. 項目不希望引入第三方庫(增加本項目的學(xué)習(xí)曲線和周期,并帶來復(fù)雜性)
  3. 項目要考慮兼容ES5標(biāo)準(zhǔn)(不使用ES6語法)
  4. 項目希望用JS原生功能完成目標(biāo)。(TypeScript最終也要轉(zhuǎn)譯為JS代碼,如果TS能夠?qū)崿F(xiàn)需求,那么JS當(dāng)然也能。通過掌握J(rèn)S,可以推測TS的轉(zhuǎn)譯邏輯。作為學(xué)習(xí),不錯。)

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

var myNamespace =
{

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

          ...
    }

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

          ...
    }

}

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

像Java,C#那樣,用面向?qū)ο蟮乃悸穪碓O(shè)計復(fù)雜的庫(或軟件系統(tǒng))。該系統(tǒng)要能夠

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

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

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

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

首先你這個例子不應(yīng)該出現(xiàn)類名重復(fù)的情況.為什么不在構(gòu)造函數(shù)中傳入?yún)?shù)來實例化.
記住在編寫代碼之前,先保證設(shè)計的合理性!不要試圖解決錯誤的邏輯.

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

所以我的建議是.

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