前端入门篇(三十八)JS基础5函数

函数定义、形参、实参

1.函数作用:代码的复用

2.函数格式:
function 函数名(形参) {
执行语句
return结果;
}

3.函数调用
var 返回值 = 函数名(实参);

4.函数重命名:
var 新函数名 = 旧函数名;
可以以var 返回值 = 新函数名(实参);调用

5.匿名函数的定义

var func1 = function () {
     
    console.log('匿名函数')
}
func1();//调用

函数的arguments

参数默认值

当实参传给形参个数不够时,形参会出现undefined的情况,此时我们可以给参数添加默认值
未设置默认值:

function slogan(num, time) {
     
    for(var a = 1; a <= num; a++){
     
        console.log(time + '点' + a + '好好学习天天向上');
    }
    
}
slogan(10)
slogan(10,5)

结果:

3.js:100 undefined点1好好学习天天向上
3.js:100 undefined点2好好学习天天向上
3.js:100 undefined点3好好学习天天向上
3.js:100 undefined点4好好学习天天向上
3.js:100 undefined点5好好学习天天向上
3.js:100 undefined点6好好学习天天向上
3.js:100 undefined点7好好学习天天向上
3.js:100 undefined点8好好学习天天向上
3.js:100 undefined点9好好学习天天向上
3.js:100 undefined点10好好学习天天向上
3.js:100 51好好学习天天向上
3.js:100 52好好学习天天向上
3.js:100 53好好学习天天向上
3.js:100 54好好学习天天向上
3.js:100 55好好学习天天向上
3.js:100 56好好学习天天向上
3.js:100 57好好学习天天向上
3.js:100 58好好学习天天向上
3.js:100 59好好学习天天向上
3.js:100 510好好学习天天向上

设置默认值:

//方法一:
function slogan(num, time) {
     
    if (time == undefined){
     
        time = 7;
    }

    for(var a = 1; a <= num; a++){
     
        console.log(time + '点' + a + '好好学习天天向上');
    }
    
}
slogan(10)
slogan(10,5)
//方法二:
function slogan(num, time) {
     
    time = time || 8;
    for(var a = 1; a <= num; a++){
     
        console.log(time + '点' + a + '好好学习天天向上');
    }
    
}
slogan(10)
slogan(10,5)

设置了默认值的变量,在形参定义时要靠后,默认居后;

如:time设置了默认值,就要放在最后,实参传进去的时候,会先填没有设置默认值的参数age,要是time没有传实参,就用默认值,是个可选项

动态参数:

实参以数组arguments形式传给形参

当没有设置动态参数,且实参个数大于形参个数时,只会操作形参对应数据,剩下的参数不做处理

function add(x, y) {
     
    return x + y;
}
var res = add(3,5,6,7);
console.log(res);
//结果为:8

此时:
arguments => [3,4,6,7]
x = arguments[0]
y = arguments[1]
函数的结果只计算x+y,等于8

设置动态参数,即循环处理传入的实参

function add() {
     
    var z = 0;
    for (var i = 0; i < arguments.length; i++){
     
        z += arguments[i];
    }
    return z;
}
var res = add(3,5,6,7);
console.log(res);
//结果为:21

函数的作用域

1.作用域的定义:可访问变量的集合(对象,函数);定义了一个变量,这个变量可以被使用的范围
2. 分类(以函数做划分点):

	全局作用域(变量):
		在函数外定义的变量,在所有地方都能被访问;
			
	局部作用域(变量):
		在函数里定义的变量,只能在定义该变量的函数中使用

2.1在函数内如果修改了全局变量,全局变量是真的被修改了:

function add(){
     
    y = 100;
    console.log('add():' + y);
}
var y = 1;
add();

console.log('全局:' + y);
/*
结果输出:
add():100
全局:100
*/

2.2当全局变量和局部变量的变量名一致时:
局部变量不影响全局变量,其作用范围只在函数内;
全局变量也不能影响局部变量,其优先级低于局部变量

function add(){
     
    var y = 100;
    console.log('add():' + y);
}
var y = 1;
add();

console.log('全局:' + y);
/*
结果输出:
add():100
全局:1
*/

2.3当没有定义某全局变量y,在局部变量中也没有定义,而是直接使用,系统会将该变量视为全局变量(会引起歧义,非特殊情况还是不要这样使用)

function add(){
     
    y = 100;
    console.log('add():' + y);
}
// var y = 1;
add();

console.log('全局:' + y);
/*
结果输出:
add():100
全局:100
*/

函数预解析

1.浏览器获得js文件之后,不会立刻执行代码,而是全篇快速扫描一遍,把变量预先解析,把变量的声明代码提前

console.log('log:x = ' + x);
var x = 10;

add()
function add(){
     
    console.log('add()');
}
/*
结果是:
log:x = undefined
add()
*/

预解析会将x和add函数的声明提前,即在代码最前面隐形地加上:

var x;
function add();

2.函数也是变量;函数体不会被提前,但函数体内部的局部变量也会有预解析,隐形地加在函数体内最上方
2.1函数add()里局部变量会被预解析:

add()
function add(){
     
    y = 100;
    var y = 1;
    console.log('add():y = ' + y);
}
console.log('全局中y = ' + y);
/*
add():y = 1
Uncaught ReferenceError: y is not defined
*/

本来add()函数中,在没有全局变量定义的情况下直接使用y,系统会将y变成全局变量,但是预解析使得代码前面被隐形地加上了var y;,即:

add()
function add(){
     
	var y;
    y = 100;
    var y = 1;
    console.log('add():y = ' + y);
}
console.log('全局中y = ' + y);

因此add()函数里的y依然是局部变量,在全局环境下使用console.log就会报错

2.2当没有定义全局变量,却在函数中直接使用,即该变量为全局变量时,预解析会把该变量的声明加到函数声明之后

add()
function add(){
     
    y = 100;
    // var y = 1;
    console.log('add():y = ' + y);
}
console.log('全局中y = ' + y);

相当于:

function add();
var y;

add()
function add(){
     
    y = 100;
    // var y = 1;
    console.log('add():y = ' + y);
}
console.log('全局中y = ' + y);
/*
结果是:
add():y = 100
全局中y = 100
*/

2.3由于预解析的顺序是从上到下的,要在预解析函数之后才会扫到函数里,所以,如果在函数调用之前使用这个伪·局部变量,会报错:

console.log('全局中y = ' + y);
add()
function add(){
     
    y = 100;
    // var y = 1;
    console.log('add():y = ' + y);
}
//Uncaught ReferenceError: y is not defined
add();
add1();

function add(){
     
    y = 100;
    // var y = 1;
    console.log('add():y = ' + y);
}
console.log('全局中y = ' + y);

function add1(){
     
    y = 1;
    console.log('add1():y = ' + y);
}
console.log('全局中y1 = ' + y);
//全局中的y都是1,
//因为预解析只是将声明提前,y是全局变量,全局唯一,
//第二次扫到时,因为已经预解析了一次,就不会再次预解析,add1()对y的操作只是修改

总结预解析:
1.从上到下扫描
2.先提前全局变量和函数的声明
3.再将函数体内的全局变量(伪局部变量)提前
4.函数体内的局部变量也会有预解析,但只会提前到函数体内最前方

闭包

变量的私有化问题,使局部变量拥有全局变量的生命周期,又依然保持局部变量的性质
全局变量的生命周期贯穿整个页面开启的时间
局部变量的生命周期只在定义该变量的函数的花括号之内

背景:
如果要实现计数器的功能,每调用一次函数都加1

function count(){
     
    var counter = 0;
    counter += 1;
    console.log('count():'+counter);
}

count();
count();

由于每次调用count()函数,计数器counter都被清零,所以两次调用,结果都是1;

想要实现每次调用都让counter加1,就要将其改成全局变量;

但全局变量可以被任何人修改,有可能被其他函数修改,不安全,容易出bug,因此引入闭包来解决此问题:

//闭包
function count(){
     
    var counter = 0;//局部变量
    plus = function (){
       //匿名函数,且plus是全局的
        counter++;
        console.log('count():'+counter);
    }
}
count();//要先调用count()函数,初始化counter
plus();
plus();

当在全局访问counter时访问不到,counter变量只能在count()函数中使用

//闭包
function count(){
     
    var counter = 0;
    plus = function (){
     
        counter++;
        console.log('count():'+counter);
    }
}
count();
plus();
plus();
console.log('count():'+counter);
/*
结果:
count():1
count():2
Uncaught ReferenceError: counter is not defined
*/

由此,counter就变成了一个伪·局部变量,拥有全局变量的生命周期,但保留了局部变量的私有性质

可以简化为:

function count(){
     
    var counter = 0;
    var plus = function(){
     
        counter++;
        console.log('count():'+counter);
    }
    return plus;
}
var plus = count();
plus();
plus();

再进一步简化为:

function count(){
     
    var counter = 0;
    return function plus(){
     
        counter++;
        console.log('count():'+counter);
    };
}
var plus = count();
plus();
plus();

函数的立即执行

把函数声明和执行放在一起
count()是函数的执行,立即执行则变为(count)(),前面的(count)可以看作是用一个小括号括起的函数体:
则count()函数的立即执行为:

(function(){
     
    var counter = 0;
    var plus = function(){
     
        counter++;
        console.log('count():'+counter);
    }
    return plus;
})()

这种方式是闭包的传统方式

var plus = (function(){
     
    var counter = 0;
    var plus = function(){
     
        counter++;
        console.log('count():'+counter);
    }
    return plus;
})()
plus();
plus();

效果一致

你可能感兴趣的:(前端入门,javascript)