方法与函数的区别,以及其他问题

59

对于JS来说,这两者有什么区别?我知道方法与对象相关联,但是不明白函数的作用是什么?它们的语法又有何不同?

此外,这两种语法有什么区别:

var myFirstFunc = function(param) {
    //Do something
};

function myFirstFunc(param) {
    //Do something
};

另外,我在某个地方看到,在使用函数之前需要做类似于这样的事情:

Also, 我 saw somewhere that 我们需要 do something like this before using a function:

obj.myFirstFunc = myFirstFunc;
obj.myFirstFunc("param");

第一行代码为什么是必需的,它的作用是什么?

如果我的问题太基础了,那我道歉,因为我刚开始学习JS而感到困惑。

编辑:对于最后一部分代码,这就是我所说的:

// here we define our method using "this", before we even introduce bob
var setAge = function (newAge) {
  this.age = newAge;
};
// now we make bob
var bob = new Object();
bob.age = 30;
// and down here we just use the method we already made
bob.setAge = setAge;

1
寻找“函数声明与函数表达式”。 - elclanrs
你在哪里看到最后一部分的代码?除非obj.myFirstFunc未定义且需要引用myFirstFunc,否则没有理由这样做。 - Michael Berkowski
@MichaelBerkowski:Codecademy。我记不得具体的练习了,但代码已经找到,现在正在编辑原帖。 - Karan Goel
回答最后一个问题(这样它就不会再烦我了):他们定义了一个函数并将其赋值给 myFirstFunc。他们还有一个变量 obj,它是一个带有属性 myFirstFunc 的类。他们正在将该函数从局部变量复制到对象中。复制不需要从局部变量调用函数( myFirstFunc("param"); )。但是如果您想从对象中调用函数( obj.myFirstFunc("param"); ),尤其是当局部变量超出范围时,就需要复制。 - Trisped
8个回答

65
回答您的标题问题,即“函数”和“方法”之间的区别。
这是语义问题,与您要表达的内容有关。
在JavaScript中,每个函数都是一个对象。对象是键值对的集合。如果一个值是原始类型(数字、字符串、布尔值)或另一个对象,则该值被视为属性。如果一个值是函数,则称为“方法”。
在对象范围内,函数被称为该对象的方法。它从对象命名空间调用MyObj.theMethod()。由于我们说过函数是一个对象,因此函数内部的函数可以被视为该函数的方法。
您可以说:“我将使用我的对象的保存方法。”以及“此保存方法接受函数作为参数。”但通常不会说函数接受方法作为参数。
Btw,书籍《JavaScript Patterns》由Stoyan Stefanov撰写,详细介绍了您的问题,如果您真正想了解这门语言,我强烈推荐它。以下是书中关于此主题的引用:
“因此,一个函数A作为一个对象可能有属性和方法,其中一个方法恰好是另一个函数B。然后,B可以接受一个函数C作为参数,并在执行时返回另一个函数D。”

1
根据这个答案,仅仅说“如果一个值是函数,它被称为‘方法’”似乎不太准确? - Tina Chen
1
@TinaChen,你说得对。这个答案反映了2013年JavaScript的状态,需要更新为ES6。坦白地说,整个问题并不是那么重要。无论你怎么称呼它:函数/方法。一个函数通常在顶层(全局)命名空间中,而一个方法属于类/对象命名空间,并且必须使用该接收器调用。 - mastaBlasta
2
原始类型包括数字、字符串和布尔值。 - elin

36

有一点小区别 -

方法:当对象与其关联时,方法是一个函数。

var obj = {
name : "John snow",
work : function someFun(paramA, paramB) {
    // some code..
}

功能:当没有对象与其相关联时,它成为函数。

function fun(param1, param2){
// some code...
}

很好,简单明了的答案。 - Mike

23

很多答案都说一个方法是定义在对象上的函数的名称。

虽然这通常在谈论JavaScript或面向对象编程时使用该词语是正确的(参见这里),但值得注意的是,在ES6中,方法这个术语已经具有了非常具体的含义(请参见规范的第14.3节方法定义)。


方法定义

一个方法(严格意义上的)是通过简洁的方法语法在对象字面量中定义的函数,或者作为类声明/表达式中的类方法而定义的函数:

// In object literals:
const obj = {
    method() {}
};

// In class declarations:
class MyClass {
    method() {}
}

方法的特殊性

这个答案很好地概述了方法(在严格意义上)的特殊性,即:

  1. 方法被分配了一个内部的[[HomeObject]]属性,可以使用super
  2. 方法不带有prototype属性,并且它们没有内部的 [[Construct]]方法,这意味着它们不能被使用new调用。
  3. 方法的名称不会成为该方法作用域中的一个绑定。

以下是一些例子,说明了(在严格意义上)方法与通过函数表达式定义在对象上的函数之间的差异:

示例1

const obj = {
    method() {
        super.test;         // All good!
    },
    ordinaryFunction: function ordinaryFunction() {
        super.test;         // SyntaxError: 'super' keyword unexpected here
    }
};

示例 2

const obj = {
    method() {},
    ordinaryFunction: function ordinaryFunction() {}
};

console.log( obj.ordinaryFunction.hasOwnProperty( 'prototype' ) );  // true
console.log( obj.method.hasOwnProperty( 'prototype' ) );            // false

new obj.ordinaryFunction();     // All good !
new obj.method();               // TypeError: obj.method is not a constructor

示例3

const obj = {
    method() {
        console.log( method );
    },
    ordinaryFunction: function ordinaryFunction() {
        console.log( ordinaryFunction );
    }
};

obj.ordinaryFunction()  // All good!
obj.method()            // ReferenceError: method is not defined


3
优秀的现代答案 - forresthopkinsa

2

方法是一个对象的属性,其值为函数。方法按以下格式在对象上调用:object.method()。

//这是一个名为developer的对象

 const developer = {
  name: 'Andrew',
  sayHello: function () {
    console.log('Hi there!');
  },
  favoriteLanguage: function (language) {
    console.log(`My favorite programming language is ${language}`);
  }
};

// favoriteLanguage、sayHello和name都是名为developer的对象中的属性。

现在假设您需要调用对象内部的函数favoriteLanguage。

调用方式如下:

developer.favoriteLanguage('JavaScript');

// My favorite programming language is JavaScript'

那么我们该如何命名这个:developer.favoriteLanguage('JavaScript'); 它既不是一个函数也不是一个对象?它是一个方法。


1
一个函数执行一系列语句的示例:

 function add() { 
     var a = 2; 
     var b = 3;
     var c = a + b;
     return c;
 }

1) 方法是应用于对象的函数,例如:

 var message = "Hello world!";
 var x = message.toUpperCase(); // .toUpperCase() is a built in function

2) 使用对象构造函数创建方法。一旦该方法属于该对象,您就可以将其应用于该对象。示例:

function Person(first, last, age, eyecolor) {
    this.firstName = first;
    this.lastName = last;
    this.age = age;
    this.eyeColor = eyecolor;
    this.name = function() {return this.firstName + " " + this.lastName;};
}

document.getElementById("demo").innerHTML = person.fullName(); // using the 
method 

方法的定义:方法是一个对象的属性,它是一个函数。方法的定义方式与普通函数的定义方式相同,只不过必须将其分配为对象的属性。


1

你的第一行代码是创建一个引用函数的对象。你可以像这样引用它:

myFirstFunc(param);

但是你可以将它传递给另一个函数,因为它会像这样返回该函数:
function mySecondFunction(func_param){}
mySecondFunction(myFirstFunc);

第二行代码创建了一个名为myFirstFunc的函数,可以像这样引用它:
myFirstFunc(param);

作用域受声明位置的限制,如果在任何其他函数之外声明,则属于全局作用域。但是,您可以在另一个函数内声明函数。该函数的范围仅限于其声明所在的函数。

function functionOne(){
    function functionTwo(){}; //only accessed via the functionOne scope!
}

您的最终示例是创建函数实例,然后通过对象参数进行引用。所以这个:
function myFirstFunc(param){};

obj.myFirst = myFirstFunc(); //not right!
obj.myFirst = new myFirstFunc(); //right!

obj.myFirst('something here'); //now calling the function

这段文字表明你有一个引用函数实例的对象。关键在于,如果函数改变了你存储在obj.myFirst中的引用(reference),它不会被改变。

虽然@kevin基本上是正确的,但在JS中只有函数,你可以创建更像方法而非函数的函数,例如:

function player(){

    this.stats = {
        health: 0,
        mana: 0,

        get : function(){
            return this;
        },

        set : function( stats ){
            this.health = stats.health;
            this.mana = stats.mana;
        }  
}    

你可以调用player.stats.get(),它会返回heathmana的值。因此,在这种情况下,我认为getsetplayer.stats对象的方法。

1
那真的很有帮助。我会进一步了解并在有疑问时再提问。 - Karan Goel
您所评论的“它不能作为参数传递”的说法是不正确的。 - Nicholas

0

ECMA文档

4.3.31方法: 是作为属性值的函数

注意:当一个函数作为对象的方法被调用时,该对象会作为函数的this值传递。

很清楚:当你调用一个函数时,如果它隐式地有一个this(指向一个对象),并且如果你不能在没有对象的情况下调用该函数,那么该函数就应该被称为方法


0
var myFirstFunc = function(param) {
    //Do something
};

并且

function myFirstFunc(param) {
    //Do something
};

两者(几乎)完全相同。第二个通常只是简写。然而,正如这个jsfiddle(http://jsfiddle.net/cu2Sy/)所示,function myFirstFunc将导致函数在进入封闭作用域时被定义,而myFirstFunc = function仅在执行到该行时才创建它。

至于方法,它们有一个this参数,即当前对象,因此:

var obj = {};
obj.func = function( ) {
    // here, "this" is obj
    this.test = 2;
}
console.log( obj.test ); // undefined
obj.func( );
console.log( obj.test ); // 2

你展示的确切语法是因为你也可以这样做:

function abc( ) {
    this.test = 2;
}
var obj = {};
obj.func = abc;
obj.func( ); // sets obj.test to 2

但是如果没有充分的理由,你不应该这样做。


1
不是我点的踩,但可能是因为第一个是FunctionExpression,第二个是FunctionDeclaration,它们之间的区别在于它们何时被创建。第一个是在执行那行代码时创建的,而第二个是在任何代码被执行之前就已经被创建了。 - RobG
@user2059238:我想不出一个简单好用的理由,但在一个具有回调函数(函数可以作为参数传递)的库函数中可能需要它,或者如果你有两种可选行为(obj.doYourThing = isAngel ? myGoodFunc : myBadFunc),尽管第二种方式相当愚蠢。它还允许您定义私有函数,如果您正在使用闭包,则这些函数也是公共的(但只有在使用优化编译器时才会带来任何好处)。 - Dave
是的,因为你需要将它设置为某个值!我的观点是,你应该使用 bob.setAge = function(){whatever} 而不是 function blah(){whatever};bob.setAge=blah;。后者是不好的,因为它会污染作用域中的变量,并留下一个只有在应用于对象时才有意义的函数(如果你在函数中使用了 this,那么只有当应用于对象时才是安全的)。 - Dave

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接