Возврат расширенных типов JavaScript - PullRequest
7 голосов
/ 11 февраля 2011

Я на самом деле изучаю Крокфордский 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

Ответы [ 3 ]

5 голосов
/ 11 февраля 2011

Я отправил электронное письмо Дугласу Крокфорду сегодня днем ​​с этим вопросом, и его ответ был:

F.method (a) .method (b) .method (в)

Я не шучу.Это была только вещь, которую он написал.

Во всяком случае, мое личное понимание его (загадочного) ответа: Создание метода цепочки :

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|
5 голосов
/ 11 февраля 2011

позвольте мне попытаться объяснить это. Я не читал эту книгу, но в статье Классическое наследование в JavaScript Дугласа Крокфорда есть одно важное предложение, относящееся к этому примеру о Function.prototype.method:

Это возвращает это. Когда я пишу метод что не нужно возвращать значение, я обычно это вернуть. Это позволяет для каскадного программирования.

на самом деле я не знаком с этим термином, я думаю, что хорошо известным термином является « Свободный интерфейс » или «Метод цепочки», прочитайте эту страницу вики, есть примеры на разных языках, так что вы поймете это ..

PS. @ Джанлука Барджелли был немного быстрее, чтобы привести пример использования 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 - описание этого шаблона Мартином Фаулером
Свободные интерфейсы в PHP
Еженедельный исходный код 14 - Fluent Interface Edition - для меня достаточно коротким и достаточно хорошим, чтобы видеть плюсы и минусы (а также ссылки на другие ресурсы)

0 голосов
/ 11 февраля 2011

Я не совсем понимаю, о чем вы спрашиваете, но если вы ничего не вернете, вы ничего не назначите Function.prototype.method, что делает предложение бесполезным, не правда ли?

...