我们学完了大部分对象创建模式相关的内容, 下面还有一些小而精的部分.
七, 对象常量
JavaScript 中没有常量的概念, 虽然许多现代的编程环境可能为您提供了用以创建常量的 const 语句. 作为一种变通方案, JavaScript 中常见的一种方法是使用命名约定, 使那些不应该被修改的变量全部用大写字母以突出显示. 实际上这个命名约定已经用于内置 JavaScript 对象中了.
- console.log(Math.PI);
- console.log(Math.SQRT2);
对于您自己的常量, 也可以采用相同的命名约定, 并且将它们以静态属性的方式添加到构造函数中.
- // 构造函数
- var Widget = function () {
- // 实现...
- };
- // 常数
- Widget.MAX_HEIGHT = 320;
- Widget.MAX_WIDTH = 480;
同样的命名约定还可应用于以字面量创建的对象中, 这些常量可以是以大写字母命名的正常属性.
如果你真的想拥有一个不可变的值, 可以创建一个私有属性并提供一个取值 (getter) 方法, 但并不提供设值函数(setter). 不过在许多情况下, 当可以采用简单的命名公约取值时, 这种不提供设置函数的方法可能显得矫枉过正.
下面是一个通用的 constant(常量)对象实现方法示例, 它提供了下列方法:
set(name, value)
定义一个新的常量.
isDefined(name)
检测是定常量是否存在.
get(name)
读取指定常量的值.
在这个实现中, 只有原始值 (primitive value) 允许设为常量. 此外, 一些额外的注意事项是要确保声明的常量与内置属性名不会冲突, 比如 toString 或 hasOwnProperty 等, 可以通过使用 hasOwnProperty()检测名称, 并且在所有的常量名前面添加随机生成的前缀, 从而确保名称之间相互适应.
- var constant = (function () {
- var constants = {},
- ownProp = Object.prototype.hasOwnProperty,
- allowed = {
- string:1,
- number:1,
- boolean:1
- },
- prefix = (Math.random() + "_").slice(2);
- return {
- set:function(name,value) {
- if(this.isDefined(name)) {
- return false;
- }
- if(!ownProp.call(allowed,typeof value)){
- return false;
- }
- constants[prefix + name] = value;
- return true;
- },
- isDefined:function(name) {
- return ownProp.call(constants,prefix + name);
- },
- get:function(name) {
- if(this.isDefined(name)){
- return constants[prefix + name];
- }
- return null;
- }
- }
- }());
- // 测试以上实现代码
- // 检查是否已经定义
- constant.isDefined("maxwidth");
- // 定义
- constant.set('maxwidth',480);
- // 再次检查
- constant.isDefined('maxwidth');
- // 试图重新定义
- constant.set("maxwidth",320);
- // 该值是否扔保持不变
- constant.get("maxwidth");
八, 链模式
链模式 (Chaining Pattern) 可以使您能够一个接一个的调用对象的方法, 而无需将前一个操作返回的值赋给变量, 并且无需将您的调用分割成多行:
myobj.method1("hello").method2().method3("world").method4();
当创建的方法返回的是无任何意义的值时, 可以使它们返回 this, 即正在使用的对象的示例. 这将使对象的用户调用前面连接的下一个方法:
- var obj = {
- value:1,
- increment: function () {
- this.value += 1;
- return this;
- },
- add: function(v) {
- this.value += v;
- return this;
- },
- shout:function () {
- alert(this.value);
- }
- };
- // 链方法调用
- obj.increment().add(3).shout();
链模式的优点和缺点
使用链模式的一个优点在于可以节省一些输入的字符, 并且还可以创建更简洁的代码, 使其读起来就像一个句子.
另一个优点在于它可以帮助您考虑分割函数, 以创建更加简短, 具有特定功能的函数, 而不是创建尝试实现太多功能的函数. 从长远来看, 这提高了代码的可维护性.
链模式的一个缺点在于以这种方式编写的代码更加难以调试. 或许直到在某个特定的代码行中发生错误, 但是在此行中实际执行了太多步骤. 当链中多个方法其中一个静默失效时, 无法直到是哪一个方法失效了.
在任何情况下, 识别出这种模式都很有好处. 当编写的方法并没有明显和有意义的返回值时, 可以总是返回 this. 该模式得到了广泛的应用, 比如在 jQuery 库中就使用了该模式. 此外, 如果查看 DOM 的 API, 那么还可以注意到它的结构也倾向于链模式.
九, method()方法
JavaScript 可能会使用那些以类的方式思考的程序员感到困惑. 这就是为什么一些开发人员倾向于选择使 JavaScript 更加类似类. 其中一个这样的尝试是 Douglas Crockford 引入 method()方法的思想. 现在回想起来, 他承认使 JavaScript 类似类的思想并不是值得推荐的方案, 但是它仍然是一种令人关注的模式, 有可能在一些应用程序中遇到这种模式.
使用构造函数看起来就像是在使用 Java 中的类. 它们还能够支持您向构造函数主体中的 this 添加实例属性. 然后这种向 this 添加方法的机制其实效率十分低下, 原因在于它们最终都会与每个实例一起被重新创建, 并且消耗更多的内存空间. 这也就是为什么可服用方法应该添加到构造函数的 prototype 属性中的原因.
向编程语言中添加便利的功能通常也称之为语法糖. 在这种情况下, method()方法也可以称之为 "糖方法(sugar method)".
使用 method()定义类的方法形式如下:
- var Person = function (name) {
- this.name = name;
- }.
- method('getName',function() {
- return this.name
- }).
- method('setName',function(name) {
- this.name = name;
- return this;
- })
请注意构造函数是如何连接到 method()的调用, 其依次连接到下一个 method()的调用, 后面以此类推. 这个例子遵循了前面介绍的链模式, 它可以帮助您以单个声明语句定义整个 "类".
method()方法有两个参数: 新方法的名称, 方法的实现.
- var a = new Person('Adam');
- a.getName();
- a.setName('Eve').getName();
- // 再次强调, 请注意链模式已经生效, 这是因为 setName()返回了 this, 从而使得以上代码可以正常运行.
- // 最后, 我们看一下 method()方法是如何实现的:
- if(typeof Function.prototype.metho !== 'function') {
- Function.prototype.method = function (name,implementation) {
- this.prototype[name] = implementation;
- return this;
- };
- }
在 method()的实现中, 首先我们应该认真的检查该方法是否已经实现过. 如果没有, 那么继续添加函数, 并将其作为 implementation 参数传递给构造函数的原型. 在这种情况下, this 指的是构造函数, 其原型得到了增强.
对象创建模式的内容到这里就告一段落了, 这一整章文章讲解了命名空间模式, 声明依赖, 私有模式, 模块模式以及沙箱模式, 对象常量, 链模式等一系列有用的创建对象的方法. 那么下一章, 我们会学习下代码复用模式. 很重要哦.
来源: https://www.cnblogs.com/zaking/p/12622341.html