JS函数
JS函数
函数
使用function关键字定义函数,function是功能的意思
function fun(){
// 函数体语句
}
函数表达式
var fun = function() {
//函数体语句
}
函数声明的提升,和变量声明提升类似,函数声明也可以被提升
fun();
//预解析阶段会被提升
function fun(){
alert("函数被执行")
}
函数表达式不能提升,如果函数是用函数表达式的写法定义,则没有提升特性
fun(); //引发错误
// 只是提升变量而已
var fun = function(){
alert("函数被执行")
}
函数优先提升
fun();
//变量声明提升,无法覆盖提升的函数
var fun = function(){
alert('a');
}
//函数优先提升
function fun(){
alert('b');
}
fun();
函数的参数
参数是函数内的一些待定值,在调用函数时,必须传入这些参数的具体值
函数的参数可多可少,函数可以没有参数,也可以有多个参数,多个参数之间需要用逗号隔开
//圆括号中定义“形式参数”
function add(a,b){
var sum = a + b;
console.log(sum);
}
//调用函数时传入“实际参数”
add(3,5);
传入实参不足形参个数,剩余形参值为undefined
arguments
函数内arguments表示它接收到的实参列表,它是一个类数组对象
类数组对象:所有属性均为从0开始的自然数序列,并日有length属性,和数组类似可以用方括号书写下标访问对象的某个属性值,但是不能调用数组的方法
function fun(){
console.log(arguments);
}
fun(1,2,4,5,6);
函数的返回值
函数体内可以使用return关键字表示“函数返回值”
递归
边界条件:确定递归到何时终止,也称为递归出口
递归模式:大问题是如何分解为小问题的,也称为递归体
变量作用域
JavaScript是函数级作用域编程语言:变量只在其定义时所在的function内部有意义。
function fun() {
//fun函数就是a的作用域,变量a被称为局部变量
var a = 10;
}
fun();
console.log(a); //报错
如果不将变量定义在任何函数的内部,此时这个变量就是全局变量,它在任何函数内都可以被访问和更改。
遮蔽效应
如果函数中也定义了和全局同名的变量,则函数内的变量会将全局的变量“遮蔽”
注意变量声明提升的情况
var a = 10;
function fun(){
a++; //局部变量a被自增1,a此时是undefined,自增1的结果就是NaN
//js预解析过程,变量a的定义会被提升至函数体内所有语句之前
var a = 5;
console.log(a);
}
fun();
cosole.log(a);
形参也是局部变量
var a = 10;
function fun(a){
a++;
console.log(a);
}
fun(7);
cosole.log(a);
作用域链
一个函数内部也可以定义一个出数。和局部变量类似,定义在一个函数内部的函数是局部函数。
function fun() {
//局部函数
function inner() {
cosole.log("hello");
}
inner();
}
fun();
在函数嵌套中,变量会从内到外逐层寻找它的定义
var a = 10;
var b = 20;
function fun(){
var c = 30;
function inner() {
var a = 40;
var b =50;
//使用变量时,JS会从当前层开始,逐层向上寻找定义
console.log(a,b,c,d);
}
inner();
}
fun();
不加var将定义全局变量,在初次给变量赋值时,如果没有加var,则将定义全局变量
function fun(){
a = 3;
}
fun();
console.log(a); // 3
闭包
function fun() {
var name = 'hello';
function innerFun() {
alert(name);
}
return innerFun;
}
var inn = fun();
inn();
JavaScript中函数会产生闭包(closure)。闭包是函数本身和该函数声明时所处的环境状态的组合。
函数能够“记忆住”其定义时所处的环境,即使函数不在其定义的环境中被调用,也能访问定义时所处环境的变量。
在JavaScript中,每次创建函数时都会创建闭包。
但是,闭包特性往往需要将函数“换一个地方”执行,才能被观察出来。
闭包很有用,因为它允许我们将数据与操作该数据的函数关联起来。这与“面向对象编程”有少许相似之处。
闭包的功能:记忆性、模拟私有变量。
当闭包产生时,函数所处环境的状态会始终保持在内存中,不会在外层函数调用后被自动清除。这就是闭包的记忆性。
模拟私有变量
//封装一个函数,这个函数的功能就是私有化变量
function fun() {
var a = 0;
return {
get: function() {
return a;
},
add: function(){
a++;
}
pow: function(){
a *= 2;
}
}
}
var obj = fun();
console.log(obj.get());
obj.add();
obj.pow();
console.log(obj.get());
不能滥用闭包,否则会造成网页的性能问题,严重时可能导致内存泄露。所谓内存泄漏是指程序中己动态分配的内存由于某种原因未释放或无法释放。
立即执行函数 IIFE
IIFE(Immediately Invoked Function Expression,立即调用函数表达式)是一种特殊的JavaScript函数写法,一旦被定义,就立即被调用。
//函数外层的括号对的功能,将函数变为表达式
(function () {
statements
})();
+function () {
statements
}();
-function () {
statements
}();
函数不能直接加圆括号被调用。函数必须转为“函数表达式”才能被调用。
为变量赋值:当给变量赋值需要一些较为复杂的计算时(如if语句),使用IIFE显得语法更紧凑。 IIFE可以在一些场合(如for循环中)将全局变量变为局部变量,语法显得紧凄。
var arr = [];
for (var i = 0; i < 6; i++){
arr.push(function() {
alert(i);//变量i是全局变量,所有函数都共享内存中的同一个变量i
})
}
arr[2](); //弹出6
使用IIFE
var arr = [];
for (var i = 0; i < 6; i++){
(function(i){
arr.push(function() {
alert(i);
})
})(i)
}
arr[2](); //弹出2