1.函数作用:代码的复用
2.函数格式:
function 函数名(形参) {
执行语句
return结果;
}
3.函数调用
var 返回值 = 函数名(实参);
4.函数重命名:
var 新函数名 = 旧函数名;
可以以var 返回值 = 新函数名(实参);
调用
5.匿名函数的定义
var func1 = function () {
console.log('匿名函数')
}
func1();//调用
当实参传给形参个数不够时,形参会出现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 5点1好好学习天天向上
3.js:100 5点2好好学习天天向上
3.js:100 5点3好好学习天天向上
3.js:100 5点4好好学习天天向上
3.js:100 5点5好好学习天天向上
3.js:100 5点6好好学习天天向上
3.js:100 5点7好好学习天天向上
3.js:100 5点8好好学习天天向上
3.js:100 5点9好好学习天天向上
3.js:100 5点10好好学习天天向上
设置默认值:
//方法一:
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();
效果一致