本文详解JavaScript中创建函数的三种主要方式:函数声明、函数表达式(含自执行函数)以及Function构造函数。重点解析了函数提升机制、执行时机差异、作用域规则及性能影响,帮助开发者根据场景选择最合适的定义方法。
函数声明与函数表达式的区别
第一种方式是函数声明(Function Declaration)。
function sum1(n1,n2){
return n1+n2;
};
第二种方式是函数表达式,也常被称为函数字面量(Function Expression)。
var sum2=function(n1,n2){
return n1+n2;
};
这两种方式的核心区别在于解析器的处理时机:函数声明会被提升至当前作用域的顶部,因此在执行任何代码之前,该函数即可被调用;而函数表达式则必须等待代码执行流到达定义该行时,才会被解析并创建函数对象。
自执行函数的作用与写法
自执行函数(Immediately Invoked Function Expression, IIFE)在严格意义上属于函数表达式的一种特殊形式。它的主要目的是创建独立的作用域,确保内部声明的变量不会污染全局或其他外部作用域。这类函数通常以匿名函数形式存在,并在定义后立即自动执行。
(function(n1,n2){
console.log (n1+n2)
})(1,3);//4
除了标准的匿名自执行函数外,还有多种写法可以实现自执行效果:
//可用来传参
(function(x,y){
console.log(x+y);
})(2,3);
//带返回值
var sum=(function(x,y){
return x+y;
})(2,3);
console.log(sum);
~function(){
var name='~'
console.log(name);
}();
!function(){
var name='!'
console.log(name);
}();
;(function(){
var name=';'
console.log(name);
})();
-function(){
var name='-'
console.log(name);
}();
//逗号运算符
1,function(){
var name=',';
console.log(name);
}();
//异或
1^function(){
var name='^';
console.log(name);
}();
//比较运算符
1>function(){
var name='>';
console.log(name);
}();
~+-!(function(){
var name='~+-!';
console.log(name);
})();
~!(function(){
var name='~!';
console.log(name);
})();
(function(){
var name='call';
console.log(name);
}).call();
(function(){
var name='apply';
console.log(name);
}).apply();
Function构造函数的性能与局限
第三种方式是使用Function构造函数来创建函数,其参数必须作为字符串传入。
var sum3=new Function('n1','n2','return n1+n2');
console.log(sum3(2,3));//5
从技术实现角度看,Function构造函数本质上也是一种函数表达式。但通常不建议使用这种方式,因为它会导致代码被解析两次:首先是常规的ECMAScript代码解析,其次是对传入构造函数的字符串进行解析,这会显著降低运行性能。
var name='haoxl';
function fun(){
var name='lili';
return new Function('return name');//不能获取局部变量
}
console.log(fun()());//haoxl
Function()构造函数在每次执行时都会重新解析函数主体并创建新的函数对象,因此在循环或高频调用的场景中效率极低。相比之下,函数字面量仅在定义时编译一次。此外,Function构造函数创建的函数不遵循典型的作用域链,它始终将内部代码视为顶级函数执行,因此无法访问局部变量。