【问题标题】:JavaScript extending types returnJavaScript 扩展类型返回
【发布时间】:2011-06-25 10:58:14
【问题描述】:

我实际上正在研究 Crockford 的 Javascript:好的部分。我是 JavaScript 新手,所以很难理解这段代码的工作原理:

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};

这是我的想法:

作为一个方法(对象内部的函数),this 指向Function 对象,但是为什么需要返回该对象,因为我可以从方法内部访问它?如果我是对的,this 是参考,而不是本地副本,所以:

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
};

应该也可以。

另一方面,在 JavaScript 中,没有 return 语句的函数返回 undefined 并将其分配给 Function.prototype.method

问题

返回this有什么意义?


工作示例 #1

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
    return this;
};
var add = function(a, b) {
    return a+b;
};

Function.method('add', add);
var f = function() {};

print(f.add(1,2));

Number.method('integer', function () {
        return Math[this < 0 ? 'ceil' : 'floor'](this);
        });

print((-10/3).integer());

输出:

-3 3


工作示例 #2

Function.prototype.method = function (name, func) {
    this.prototype[name] = func;
};

var add = function(a, b) {
    return a+b;
};

Function.method('add', add);
var f = function() {};

print(f.add(1,2));

Number.method('integer', function () {
        return Math[this < 0 ? 'ceil' : 'floor'](this);
        });

print((-10/3).integer());

输出:

-3 3

【问题讨论】:

    标签: javascript extension-methods prototypal-inheritance function-prototypes


    【解决方案1】:

    让我试着解释一下。我没看过那本书,但是 Douglas Crockford 的一篇文章Classical Inheritance in JavaScript 有一个重要的句子,与那个关于 Function.prototype.method 的例子有关:

    它返回这个。当我写一个方法 不需要返回值,我 通常让它返回这个。它允许 用于级联式编程。

    其实我对这个词并不熟悉,我认为众所周知的词是“Fluent Interface”或“方法链”,阅读那个 wiki 页面,有不同语言的示例,所以你会理解它..

    PS。 @Gianluca Bargelli 以这种方式提供使用 Function.prototype.method 的示例要快一些,所以我不会在我的答案中发布它

    ADDON:根据您的示例如何使用它:

    Function.prototype.method = function (name, func) {
        this.prototype[name] = func;
        return this;
    }
    
    Number.method('integer', function () {  // you add 'integer' method
            return Math[this < 0 ? 'ceil' : 'floor'](this);
            })
          .method('square', function () {  // you add 'square' method with help of chaining
            return this * this;
            });
    
    console.info( (-10/3).integer().square() ); // <- again chaining in action
    

    你看,integer() 返回 Number 对象,所以你可以调用另一个方法,而不是写:

    var a = (-10/3).integer();
    console.info( a.square() ); 
    

    关于我使用它的方式的几句话,大多数时候我更喜欢写“每个方法 - 带有缩进的新行,对我来说这种方式更具可读性:

    Function.method('add', add)
            .method('sub', sub)
            .method('mul', mul)
            .method('div', div);
    

    这样我可以看到我从哪里开始,并且“新行/缩进”告诉我我仍在修改那个对象。将其与长线进行比较:

    Function.method('add', add).method('sub', sub).method('mul', mul).method('div', div);
    

    或典型方法:

    Function.method('add', add);
    Function.method('sub', sub);
    Function.method('mul', mul);
    Function.method('div', div);
    

    ADDON2: 通常我在处理实体时使用这种方法(Fluent 接口模式),例如Java 代码:

    public class Person {
      private String name;
      private int age;
      ..
    
      public String getName() {
        return this.name;
      }
    
      public Person setName( String newName ) {
        this.name = newName;
        return this;
      }
    
      public int getAge() {
        return this.age;
      }
    
      public Person setAge( int newAge ) {
        this.age = newAge;
        return this;
      }
    
      ..
    }
    

    它允许我以简单的方式构造Person 对象:

    Person person = new Person().setName("Leo").setAge(20);
    

    有些人让它有点不同,他们在set/get中添加了新的方法,并称之为with

    public class Person {
      private String name;
      private int age;
      ..
    
      public String getName() {
        return this.name;
      }
    
      public void setName( String newName ) {
        this.name = newName;
      }
    
      public Person withName( String newName ) {
        this.setName( newName ); // or this.name = newName; up to you
        return this;
      }
    
      public int getAge() {
        return this.age;
      }
    
      public void setAge( int newAge ) {
        this.age = newAge;
      }
    
      public Person withAge( int newAge ) {
        this.setAge( newAge ); // or this.age = newAge; up to you
        return this;
      }
      ..
    }
    

    现在我之前的例子看起来像:

    Person person = new Person().withName("Leo").withAge(20);
    

    这样我们不会改变 set 方法的含义(我的意思是我们不会增强它,所以它可以像大多数开发人员期望的那样工作......至少人们不期望set 方法可以返回任何东西; ))。关于这些特殊方法的一件有趣的事情是——它们可以失去自我记录,但是当你使用它们时它们会提高可读性(例如 Person 创建的例子,withName 很好地说明了我们到底在做什么......

    阅读更多:
    FluentInterface - Martin Fowler 对该模式的描述
    Fluent Interfaces in PHP
    The Weekly Source Code 14 - Fluent Interface Edition - 对我而言,简短且足以看到利弊(以及链接到其他资源)

    【讨论】:

    • 你是对的。都是关于方法链的,见我上面的回答。
    • 我已经回答了我自己的问题,但是如果你能提供比我更好的例子和一些关于这个主题的资源,我很乐意标记你的答案。
    • @Gianluca Bargelli,对不起,我没有注意到回复者和回答者是相同的 :) 我添加了一个示例,如果需要更多,请告诉我
    • 感谢您的努力 :) 我也投票赞成您的答案,因为它非常完整 :)
    • @Gianluca Bargelli,尽我所能:) 对于 JavaScript 示例,您可以查看 jQuery API,它非常遵循这种方式
    【解决方案2】:

    今天下午我已经发邮件给Douglas Crockford了这个问题,他的回复是:

    F.method(a).method(b).method(c)

    我不是在开玩笑。这是他唯一写的东西。

    无论如何,我个人对他(神秘)答案的解释是链方法创建

    Function.prototype.method = function (name, func) {
        this.prototype[name] = func;
        return this; //This returns the same Function object into the chain below
    };
    
    var add = function (a, b) { return a+b; };
    var sub = function (a, b) { return a-b; };
    var mul = function (a, b) { return a*b; };
    var div = function (a, b) { return a/b; };
    
    Function.method('add', add).method('sub', sub).method('mul', mul).method('div', div);
    

    也就是说,不是每次使用一个行来创建新方法,而是可以重新应用链中的下一个方法在返回对象上以前,Function

    在本例中,链条从从左到右

    |Function|--method-->|add|--returns-->|Function|--method-->|sub|--returns-->|Function|--method-->|mul|--returns-->|Function|--method-->|div|-->returns-->|Function|
    

    【讨论】:

      【解决方案3】:

      我不明白你问什么,但如果你不返回任何东西,你将不会为 Function.prototype.method 分配任何东西,女巫会让这句话毫无用处,你不觉得吗?

      【讨论】:

      • 我将用一个工作示例编辑问题;问题是 Function.prototype.method 没有设置为undefined,正如您将看到的那样。
      • 试试这个:给 Function.prototype.method 一个值。运行您询问的代码。检查下一个值...如果它已更改...我无法回答您的问题:)。如果没有......这就是你的答案。
      • 你的意思是Function.prototype.method = 2; Function.prototype.method = function (name, func) { this.prototype[name] = name; };`?最后一个赋值覆盖它。
      猜你喜欢
      • 1970-01-01
      • 2018-04-06
      • 2013-10-18
      • 2013-08-25
      • 1970-01-01
      • 2022-11-25
      • 2014-09-08
      • 2011-05-17
      • 1970-01-01
      相关资源
      最近更新 更多