题引
var funOne = function() {
// 代码
};
function funTwo() {
// 代码
}
这两种方式有什么区别?适合什么样的场景?
(资料:javaScript权威指南、 stackoverflow)
概念
函数使用function关键字来定义,它可以用在函数定义表达式或者函数声明语句里,正如题引中两种定义方式
函数定义从function关键字开始,其后跟随以下组成部分:
- 函数名称标识符(如funTwo),相当于变量的名字,新定义的函数对象会赋值给这个变量。对函数定义表达式来说是可选的,对函数声明语句来说是必须的。
- 一对圆括号(),其中包含0个或者多个参数,相当于函数体中的局部变量;
- 一对花括号 { },其中包含0条或者多条javaScript语句,这些语句构成函数体:一旦调用函数,就会执行这些语句
注:如果一个函数定义表达式包含函数名称标识符,函数的局部作用域将会包含一个绑定到函数对象的名称,意思是这个名称指代该函数对象本身,成为该函数内部的一个局部变量,(emmm,一般好像用不到,我没有用过)
var funOne = function aa() {
console.log('111')
console.log(aa) //打印 ƒ aa() { console.log('111') console.log(aa) }
};
funOne()
aa() // 报错:aa is not defined
定义
- 定义域
- 函数声明语句:
在ECMAScript5中,规范规定函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。尝试在if语句中申明函数但可能发现并没有报错,因为实际上各大浏览器出于兼容性的考虑,都没有遵守这个规范。
到了ECMAScript6时代:规范规定了块级作用域的存在,函数就可以在块级作用域中定义了。 - 函数定义表达式:同变量,可以放在任何地方
-
变量提升
// 例1 funOne = function() { var funOne ; console.log(1); (编译)===> funOne = function() { } console.log(1); var funOne ; } funOne(); // 结果:1 funOne(); // 结果:1 funTwo(); // 结果:undefined is not a function var funTwo; var funTwo= function() { funTwo(); // 结果:undefined is not a function console.log(2); (编译)===> funTwo= function() { } console.log(2); var funTwo; }
js引擎在编译阶段中,会找出代码中所有的定义声明(包括变量和函数)并关联到合适的作用域中;
// 例2 funOne (); //结果:3 function funOne () { function funOne () { (编译)===> console.log( 3); console.log( 3); } } funOne (); //结果:3
和通过var声明变量一样,函数声明语句也发生了“提前”,不同的是,使用var的话,只有变量声明提前了(变量的初始化代码任然在原来的位置),而使用函数声明,函数名称和函数体均提前:脚本中的所有函数和函数中所有嵌套的函数都会在当前上下文中其他代码之前申明,也就是说,可以在声明一个javaScript函数之前调用它。
函数调用
构成函数主体的javaScript代码在定义之时并不会执行,只有调用该函数时它们才会执行。有以下4种调用方式
- 作为函数:
var result = factorial(5)/factorial(13)
调用上下文(this的值)是全局对象Window,在严格模式下,this是undefined
"use strict"
function aa(x){
console.log(this);
return x*x;
}
var result = aa(2)/2
- 作为方法
如果函数表达式是一个属性访问表达式,即该函数是一个对象的属性或者数组中的一个元素,那么它就是一个方法调用表达式,方法调用this指向调用该方法的对象,如以下代码,this指向o
var o = {
aa:function(){
console.log(this);
},
bb:1
}
o.aa();
- 作为构造函数
如果函数或者方法调用之前带有关键字new,它就构成构造函数调用,构造函数调用创建一个新的空的对象,这个空对象的__proto__成员指向了构造函数对象的prototype成员对象,将构造函数的作用域赋给新对象,因此构造函数中的this指向新对象
var o = new Object();
- 通过它们的call()和apply()方法间接调用
JavaScript中的函数也是对象,和其他javascript对象没什么两样,函数对象也可以包含方法。其中的两个方法call()和apply()可以用来间接地调用函数,以call为例
var o = {
aa:function(){
console.log(this.p)
},
p:"123"
}
var bb={
p:"456"
}
o.aa(); // 结果:“123”
o.aa.apply(bb);// 结果:“456”
在执行o.aa()是console.log(this.p)指向的是o,所以打印的是“123”,而用call简洁调用方法aa时,将当前this指向的对象替换成了参数bb对象,所以打印的是“456”。
总结
:两种方式都创建了新的函数对象,使用的时候多注意变量提升和this的指向