Расширение JavaScript типы возвращают
На самом деле я изучаю 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 ответа:
Позвольте мне попытаться объяснить это. Я не читал эту книгу, но в статье классическое наследование в JavaScript Дугласа Крокфорда есть одно важное предложение, связанное с этим примером о функции.прототип.метод:
Он возвращает это. Когда я пишу метод это не должно возвращать значение, я обычно он возвращает это. Это позволяет для каскадного стиля программирования.
На самом деле я не знаком с этим термином, я думаю, что хорошо известный термин-это "Fluent Interface " или "Method Chaining", прочитайте эту страницу вики, там есть примеры на разных языках, так что вы поймете это..
ПС. @Gianluca Bargelli был немного быстрее, чтобы предоставить пример использования функции.прототип.метод такой, поэтому я не публикую его в своем ответе
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 interface pattern) при работе с сущностями, например 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
creation,withName
очень хорошо говорит, что именно мы делаем..Читать дальше:
FluentInterface - описание этого паттерна Мартином Фаулером
свободные интерфейсы на PHP
Еженедельный исходный код 14-Fluent Interface Edition - как по мне короткий и достаточно хороший, чтобы увидеть плюсы и минусы (а также ссылки на другие ресурсы)
Сегодня днем я отправил электронное письмо Дугласу Крокфорду с этим вопросом, и его ответ был:
F. метод (а).метод (b).метод (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|