Лучший способ определить функцию?

Я всегда научился определять функцию в JavaScript следующим образом:

function myFunction(arg1, arg2) { ... }

Однако, я просто читал руководство Google для Javascript, он упомянул, что я должен определить такие методы:

Foo.prototype.bar = function() { ... };

Вопрос: Является ли "Foo" в примере Object, или это пространство имен? Почему в примере Google не указан следующий код (который не работает):

prototype.bar = function() { ... };

UPDATE. В случае, если это поможет узнать, все мои JavaScript будут вызываться браузером пользователей для моего веб-приложения.

Ответы

Ответ 1

Два ваших примера не являются функционально эквивалентными. Первый пример просто определяет функцию (возможно, глобальную, если вы не определяете ее внутри другой функции). Второй пример расширяет прототип конструктора. Подумайте об этом как о добавлении метода к классу Foo.

Если вы не создаете библиотеку JavaScript, мое предложение состояло бы в том, чтобы не использовать ни одну из них и использовать какую-либо систему пространства имен. Создайте один глобальный объект, который действует как пространство имен, через которое вы можете получить доступ ко всем вашим функциям.

var MyObject = {
    utils: {
        someUtil: function() {},
        anotherUtil: function() {}
    },
    animation: {
        // A function that animates something?
        animate: function(element) {}
    }
};

Тогда:

// Assuming jQuery, but insert whatever library here
$('.someClass').click(function() {
    MyObject.animation.animate(this);
});

Если вы хотите эмулировать классы в JavaScript, вы должны определить "класс" как функцию (сама функция является конструктором), а затем добавить методы через свойство prototype.

function Foo() {
    // This is the constructor--initialize any properties
    this.a = 5;
}
// Add methods to the newly defined "class"
Foo.prototype = {
    doSomething: function() { /*...*/ },
    doSomethingElse: function() { /*...*/ }
};

Тогда:

var bar = new Foo();
console.log(bar.a); // 5
bar.doSomething();
// etc...

Ответ 2

Я всегда научился определять функцию в JavaScript следующим образом:   function myFunction(arg1, arg2) { ... }

Существует два способа определения функции. Либо как объявление функции

function foo(...) {
    ...
}

Или как выражение функции

var foo = function() {
    ...
};

Читать подробнее здесь.

Однако, я просто читал руководство Google по Javascript, он упомянул, что я должен определить такие методы: Foo.prototype.bar = function() { ... };

Это специально связано с созданием метода для объектов, а не только для обычных автономных функций. Предполагая, что у вас есть объявление базового объекта:

var foo = function() {
    ...
};

Как и любое другое назначение, чтобы назначить функцию объекту, вы должны использовать выражение присваивания. Вы можете сделать это двумя способами. Краткий и общий способ (как это предлагает ссылка Google)

Foo.prototype.bar = function() {};

Или, если вы хотите продолжить использование декларативной формы определяющих функций

function bar() {
    ...
};
Foo.prototype.bar = bar;

Это обычно более подробно, чем необходимо, но может быть полезно в ситуациях, когда вы хотите назначить один и тот же метод нескольким прототипам объектов.

Вопрос: Является ли "Foo" в примере Object, или это пространство имен? Почему в примере Google не используется следующий код (который не работает): prototype.bar = function() { ... };

  • Foo - это объект. Хотя концепцию можно выразить с помощью статических объектов, как я показал в ответе на ваш другой вопрос, в JavaScript не существует таких объектов, как пространства имен. Кроме того, особенно в приведенном примере кода, Foo, скорее всего, предназначен для создания объекта, который не позволяет ему вести себя как пространство имен.

  • Конечно, это не работает: prototype не был определен как объект (если, конечно, вы не определяете его как таковой). Свойство prototype существует для каждого объекта (функция также является объектом), поэтому вы можете сделать Foo.prototype.bar = ...;. Читать подробнее здесь.

Ответ 3

===== → 2017 Update < =====

Этот вопрос и ответы 7 лет и очень устарел. Этот ответ включает новый синтаксис для версий ES5, ES6 и совместим с ES7.


Лучший способ определить функцию?

Нет никакого "лучшего" способа определения функции. Как вы определяете функцию, зависит от предполагаемого использования и времени жизни функции.

Глобальные функции

Определяется как оператор с токеном функции, за которым следует имя функции с нижним регистром

function functionName (arguments) {
    // function body
}

предпочтительнее выражения функции...

var functionName = function (arguments) {
     // function body
}

... поскольку присвоение переменной функции не происходит до тех пор, пока не будет выполнена определяющая строка. В отличие от предпочтительного метода, который доступен сразу после разбора до того, как будет выполнен какой-либо код.

const functionName = function(arguments){/*function body*/}
var functionName = function functionName(arguments){/*function body*/}
var functionName = function functionAltName(arguments){/*function body*/}

Объекты функции

Как оператор функции с именем функции верхнего регистра верблюда

function MyObjectFunction (arguments) {
    /*function body*/
    // if this function is called with the new token
    // then it exits with the equivalent return this;
}

const obj = new MyObjectFunction(foo);

Анонимное выражение функции.

Общей практикой является создание объекта через сразу вызываемую функцию, которая не имеет имени (и, следовательно, анонимна)

;(function (arguments) { /*function body*/ } ("argument val"))

Или

;(function(arguments){ /*function body*/ })("argument val")

ПРИМЕЧАНИЕ включение ; для функции. Это очень важно, поскольку open "(" предотвратит автоматическую установку точки с запятой на любом коде выше функции.

Немедленно вызывается выражение функции.

const functionResult = (function (arguments) {
      /*function body*/
      return functionResult;
}());

const functionResult = (function (arguments) {
      /*function body*/
      return functionResult;
})();

Как var или область с областью const, let

Анонимный обратный вызов.

С ES6 вы должны использовать синтаксис функции стрелки, а не анонимные выражения функций.

 myArray.forEach((item,i) => {/*function body*/});
 myArray.filter(item => !item);
 setTimeout(() => {/*function body*/}, 1000);

Функция как свойства.

Использование синтаксиса сокращенной функции объявления объявления.

var myObj = {
    functionName (arguments) {/*function body*/},
}

// called 
myObj.functionName("arg");

предпочтительнее

var myObj = {
    functionName : function (arguments) {/*function body*/},
}

Или через объявления объектов функций

function MyObjectFunction(arguments){
     this.propertyFunction = function(arguments) { /*function body*/ }
     // or arrow notation is fine
     this.propertyFunction = (argument) => { /*function body*/ };
}

Функции в качестве прототипов

function MyObj (arguments) {
      MyObj.prototype.functionName = function(arguments) { /*function body*/ }
}

или

function MyObj (arguments) {}
MyObj.prototype.functionName = function(arguments) { /*function body*/ }

или

MyObj.prototype = {
    functionName(arguments) { /*function body*/ }
}

Ответ 4

Определение функции прототипа полезно при создании конструкторов или "классов" в JavaScript. например func, что вы new

var MyClass = function(){};
MyClass.prototype.doFoo = function(arg){ bar(arg); }

но он бесполезен в простых старых библиотечных функциях, например

function doPopup(message){ /* create popup */};

Существует несколько преимуществ использования прототипа, включая, помимо прочего,

  • скорость
  • Использование памяти
  • расширяемость

Но опять же, это в контексте создания конструкторов для реальных классов

НТН

Ответ 5

Он работает так:

(function(){ // create an isolated scope
    // My Object we created directly
    var myObject = {
        a: function(x,y) {
            console.log('a');
        },
        b: function(x,y) {
            console.log('b');
            this.a(x,y);
        }
    };
})();

(function(){ // create an isolated scope

    // Create a Object by using a Class + Constructor
    var myClass = function(x,y) {
        console.log('myClass: constructor');
        this.b(x,y);
    };
    myClass.prototype = {
        a: function(x,y) {
            console.log('myClass: a');
        },
        b: function(x,y) {
            console.log('myClass: b');
            this.a(x,y);
        }
    };

    // Define a function that should never inherit
    myClass.c = function(x,y) {
        console.log('myClass: c');
        this.a(x,y);
    };

    // Create Object from Class
    var myObject = new myClass();
    // Will output:
    // myClass: constructor
    // myClass: b
    // myClass: a

    // Define a function that should never inherit
    myObject.d = function(x,y) {
        console.log('myObject: d');
        this.a(x,y);
    };

    // Test the world is roung
    console.log(typeof myClass.c, 'should be undefined...');
    console.log(typeof myClass.d, 'should be function...');
})();

(function(){ // create an isolated scope
    // If you are using a framework like jQuery, you can obtain inheritance like so

    // Create a Object by using a Class + Constructor
    var myClass = function(x,y) {
        console.log('myClass: constructor');
        this.b(x,y);
    };
    myClass.prototype = {
        a: function(x,y) {
            console.log('myClass: a');
        },
        b: function(x,y) {
            console.log('myClass: b');
            this.a(x,y);
        }
    };

    // Create new Class that inherits
    var myOtherClass = function(x,y) {
        console.log('myOtherClass: constructor');
        this.b(x,y);
    };
    $.extend(myOtherClass.prototype, myClass.prototype, {
        b: function(x,y) {
            console.log('myOtherClass: b');
            this.a(x,y);
        }
    });

    // Create Object from Class
    var myOtherObject = new myOtherClass();
    // Will output:
    // myOtherClass: constructor
    // myOtherClass: b
    // myClass: a
})();

(function(){ // create an isolated scope
    // Prototypes are useful for extending existing classes for the future
    // Such that you can add methods and variables to say the String class
    // To obtain more functionality
    String.prototype.alert = function(){
        alert(this);
    };
    "Hello, this will be alerted.".alert();
    // Will alert:
    // Hello, this will be alerted.
})();

Изменить: Исправлен код, чтобы он действительно запускался в вашем браузере, если вы копируете и вставляете: -)

Ответ 6

Foo - это как Object, так и пространство имен. См. этот вопрос.

Использование объектов в качестве пространств имен предотвращает столкновения имен. Это всегда хорошая идея, но особенно когда вы разрабатываете и/или используете общие библиотеки.

Если вы не ожидаете создания нескольких объектов Foo (и, следовательно, не нуждаетесь в объектно-ориентированном стиле), вы можете создавать свои функции как методы для одноэлементного объекта:

var Foo = {}
Foo.bar = function() { ... }

или

var Foo = {
    bar: function() {...},
    quux: function() {...}
};

Затем вы просто вызываете функцию как:

Foo.bar()

(Этот вид объявления примерно эквивалентен статическому методу в С++ или Java.)