定义函数的最佳方法是什么?

时间:2010-07-18 03:41:24

标签: javascript web-applications

我总是学会在JavaScript中定义一个函数,如下所示:

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

但是,我只是在阅读Google's guide to Javascript,它提到我应该定义这样的方法:

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

问题:示例中的“Foo”是Object,还是名称空间?为什么Google示例中没有以下代码(不起作用):

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

更新:如果有必要知道,我的所有JavaScript都会被用户浏览器调用,用于我的网络应用程序。

6 个答案:

答案 0 :(得分:8)

你的两个例子在功能上并不相同。第一个示例只是定义一个函数(可能是全局函数,除非您在另一个函数中定义它)。第二个例子扩展了构造函数的原型。可以将其视为向类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...

答案 1 :(得分:7)

我总是学会在JavaScript中定义一个函数,如下所示:  function myFunction(arg1, arg2) { ... }

定义函数有两种方法。作为函数声明

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

或作为函数表达式

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

Read more here

但是,我刚刚阅读了谷歌的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() { ... };

  1. Foo是一个对象。虽然这个概念可以通过使用静态对象来表达,正如我在my answer to your other question中所示,但JavaScript中没有名称空间。此外,特别是在给出的示例代码中,Foo可能是一个实例化对象,这使得它无法像命名空间一样运行。

  2. 当然它不起作用:prototype尚未定义为对象(当然,除非您将其定义为对象)。 prototype 属性存在于每个对象上(函数也是一个对象),这就是您可以执行Foo.prototype.bar = ...;的原因。 Read more here

答案 2 :(得分:4)

=====> 2017年更新< =====

这个问题和答案是 7岁,并且非常过时。此答案包括 ES5 ES6 版本的新语法,并与 ES7 兼容。

定义函数的最佳方法是什么?

没有人" Best"定义函数的方法。如何定义函数取决于函数的预期用途和生命周期。

全球职能

定义为带有函数标记的语句,后跟带有小写camelcase的函数名

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*/}

功能对象

作为具有大写camelcase函数名称

的函数语句
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或阻止范围constlet

匿名回调。

使用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*/ }
}

答案 3 :(得分:2)

在JavaScript中创建构造函数或“类”时,定义原型函数很有用。例如你将new

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

但在普通的旧库函数中没有用,例如

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

使用原型功能有几个好处,包括但不限于

  • 速度
  • 内存使用
  • 扩展

但是,同样,这是在为可实例化的“类”

创建构造函数的上下文中

HTH

答案 4 :(得分:1)

它的工作原理如下:

(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.
})();

编辑:修复了代码,以便在您复制和粘贴时实际在浏览器中运行: - )

答案 5 :(得分:0)

Foo既是Object又是命名空间。请参阅this question

将对象用作名称空间可防止名称冲突。这总是一个好主意,尤其是在您开发和/或使用共享库时。

如果您不希望制作多个Foo对象(因此不需要面向对象的样式),您可以在单个对象上创建函数作为方法:

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

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

然后您只需将该函数调用为:

Foo.bar()

(这种声明大致相当于C ++或Java中的静态方法。)