理解JavaScript函数声明语法

3

使用 JavaScript 一段时间后,我有了一些问题。

声明函数的方式是:

var myFunction = function(param){//code here}

但还有另一种声明函数的方式,即:

function myFunction(param){//some code}

如何区分两种声明函数的方法?

我的第二个问题是,我理解你可以从一个声明为以下方式的函数创建对象:

function Person(name){this.name=name;}

然后,您可以声明另一个函数,如下所示:

function Speak(){console.log(this.name);}

Speak函数是如何知道它与Person对象相关的?

关于this关键字,请参考此处 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/this - elclanrs
你的第二个问题的答案是:当你使用 var ben = new Person("Ben"); 创建一个新的人时,然后调用 speak 并将调用对象设置为 ben:speak.call(ben); 如果 speak 是 Person 的行为,则应将其放在 Person.prototype 上:Person.prototype.speak=function()... 然后你可以执行 ben.speak(); 更多关于构造函数、原型和调用对象的信息请参考这里:https://dev59.com/J2Qo5IYBdhLWcg3wbe5K#16063711 - HMR
4个回答

1

第一个是表达式

var myFunction = function(param){//code here}

第二个是声明。
function myFunction(param){//some code}

请查看这篇文章 http://kangax.github.io/nfe/


两者都是表达式。一个只是将表达式的结果绑定到词法作用域变量。 - David-SkyMesh
@David-SkyMesh,请不要混淆概念。回答是正确的,ECMA-262 标准根据上述回答同时定义了 FunctionDeclarationFunctionExpression。前者是一个变量声明,它将变量声明和函数表达式的赋值结合在了一起,也称作初始化器。 - RobG
@RobG 毫无疑问,这就是语法产生式的称呼。但在实践中它们有何不同?根据规范,两者(减去赋值)都是产生值的表达式。语法需要两个版本,否则解析将是不可判定的。OP问,两者之间有什么区别。这篇文章并没有回答那个问题。 - David-SkyMesh
@David-SkyMesh 有所不同,请考虑下面的代码`alert(funA()); //将弹出hello` `function funA() {return "hello"}` `alert(funB()); //错误` `funB = function(){return "hello"}` - Rick Li
@RickLi 没有区别。从表达式上看,(function x (){ 1; })(function (){ 1 }) 的值是相同的。根据用途,第一种形式具有副作用;将 x "slot" 分配给 NULL(全局)范围。我说“根据”是因为您可以在某些数据结构中使用该形式(或作为其他类型的子表达式),并且它不会产生副作用。 - David-SkyMesh

0

当你使用var这个词时,你声明了一个相对于它定义的位置的变量,不能从外部访问,并且如果它在函数内部,它会在执行结束时被销毁,如果你不使用它,你就是在全局范围内定义了它,而且变量在函数执行后仍然存在。

第二件事是关于面向对象编程。

你可以像纯对象一样使用函数:

var person = {
    name: null,
    setName: function (name) {
        this.name = name
    }
}

然后你就可以访问它的属性了

person.setName('john');
console.log(person.name);

以函数的形式

function Person(name){
    this.name = null;
}

var john = new Person('John');
console.log(john.name);

0

当您使用此语法时:

function f1(){}

那么 f1 可以在当前作用域的任何地方使用:

// we can call f1 even before definition of the function
f1(); // it works

function f1(){}

但是,当我们使用这个语法时:

var f1 = function(){};

然后f1就像一个指向匿名函数的指针,可以在赋值之后使用:

// we can't call it before assignment of our var
//f1(); // f1 is undefined here!

var f1 = function(){}

// we can call it here
f1(); // works

第二种语法在考虑到每个函数也是一个对象时更有意义。例如,我们可以将一个函数作为对象的属性,就像这样:
var myObject = new Object();
myObject.say = function(x) {alert(x);};  
// myObject now has a property/method named "say"
myObject.say("Hello");

关于第二个问题:关键字this。你能给出定义你的PersonSpeak函数的代码(外部)作用域吗?你写的代码不能直接运行。如果你想在Speak函数中设置正确的this引用,你需要编写如下代码:
function Person(name){ this.name=name; }
function Speak(){ alert(this.name); }

Person.prototype.DoSpeak = Speak; //here we attach DoSpeak to Speak function

var p = new Person("Saeed"); 
p.DoSpeak(); //this will work

谢谢你的回答!关于这个人,当我在Code Academy学习时,他们使用了函数speak,就像我在问题中所做的那样,它起作用了。你有什么想法吗? - kfirba
@kfirba 我想看看,如果你明确地设置调用对象,那么 speak 只能起作用。你提供的代码会将 speak 放在全局对象(window)上,因此当你执行 speak() 时,它与 window.speak(); 相同,并且调用对象(this)将是 window,除非你使用 call 来更改调用对象:speak.call(personInstance); - HMR

0
  • 两者都是声明

    1) var myFunction = function(param){//在这里编写代码}

    这是一个分配给'myFunction'本地变量的声明

    • 您可以为该函数设置标识符,以进行调试或递归

      var myFunction = function myFunctionIdentifier(param){ console.log(myFunctionIdentifier.toString())}

      但要调用此函数,您必须使用'myFunction'变量

    • 执行嵌套调用的另一种方法是使用指向函数本身的arguments.callee

      var myFunction = function(param){ console.log(arguments.callee.toString())}

    2) function myFunction(param){//一些代码}

    这是一个分配给作用域变量的声明

    • 如果您在全局区域中(例如在浏览器中),它将被分配给window对象,因此实际上window["myFunction"]()是有效的


* 关于这个问题...

 function Person(name){this.name=name;}
 function Speak(){console.log(this.name);}

Speak“知道”人名的原因在于JavaScript作用域。由于两者使用相同的作用域,因此两个函数都使用相同的this。“例如:如果您在全局范围内编写两个函数,则this == window对象,因此console.log(window ['name'])将为您提供名称。
您不希望以这种方式编码..因为另一个使用this.name的函数将覆盖您现有的逻辑。如果您将实例化Person实体
var person = new Person();
那么person变量将是this,this == person对象,然后您可以以两种或更多方式分配Speak:
内联:
function Person() { ... this.Speak = function ... }
代码外部,因为人员分配给(Person)this
person.Speak = function() ...
或者最好的方法,使用原型对象:
Person.prototype.Speak = function() ...

1
我认为它被称为调用对象,this的值与作用域无关。 - HMR
名字不是问题...你可以随便叫它什么...函数中的'this'指向它被创建时所在的作用域(如果没有使用'new')。 - lastboy

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