如何解决js面向对象开发中的命名空间冲突

发布于 2022-09-06 06:17:44 字数 1761 浏览 23 评论 0

背景

  1. 目的是开发一套图表库,供外部使用
  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 ;

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

时光无声 2022-09-13 06:17:44

TypeScript

ES6 的超集,支持asyncPromiseyield等新语法


适合面向对象的场景

最终会编译成 es5js 代码,也就是任何浏览器可以执行的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
苄①跕圉湢 2022-09-13 06:17:44

Symbol 可以吗

无声静候 2022-09-13 06:17:44

requirejs或直接上es6使用webpack打包

日记撕了你也走了 2022-09-13 06:17:44

首先你这个例子不应该出现类名重复的情况.为什么不在构造函数中传入参数来实例化.
记住在编写代码之前,先保证设计的合理性!不要试图解决错误的逻辑.

还有现在是 es6 的时代,请自行学习 es6 的语法.来定义类.推荐 阮一峰 es6 入门
此外前端以进化到编译型.请学习 webpack 来打包代码.自行参看官方文档.

所以我的建议是.

  1. 重构你的逻辑.不应该出现同名类,因为逻辑上来说一个类代表一类实体的抽象,复用逻辑请抽离为函数库而不是类!
  2. 如果执意要实现请利用 webpack + es6 进行重构.当然前提是你要懂 node.这个就靠你自己了.
空城仅有旧梦在 2022-09-13 06:17:44

决定采用“伪命名空间”的方式解决本问题。

理由:

  1. 项目规模不大,“伪命名空间”虽然使得局部代码看起来啰嗦了一些,但是实施起来非常简单,效果很好。
  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#那样,用面向对象的思路来设计复杂的库(或软件系统)。该系统要能够

  1. 从代码文件结构上合理组织(比如Java的packge包结构)
  2. 能够在不同的packge中包>含相同类名的js类
  3. 作为功能库,在被引入时,不能够与其他任何库产生命名冲突

今后需学习的地方:
没有TS或ES6开发的经验,不好做判断。但是,仅仅通过TS和ES6中对“类”,“类继承”,“模块化”的浅显了解,个人感觉这些语法糖使得原本简单的JS代码变得复杂起来,这也是是代价。
希望有实战经验的朋友们对TS或ES6在解决本问题上做“能”或“不能”的判断,如果能够提供简单示例代码,那将非常感谢。

此问题暂时不关闭,等待有实战经验的朋友们给予指点!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文