了解函数
函数就是把特定功能的代码抽取出来并进行封装,用来重复执行一些功能,并起个名字(函数名)。函数对任何语言来说都是一个核心的概念。通过函数可以封装任意多条语句,而且可以在任何地方、任何时候调用执行
使用函数的好处,为什么要使用函数
- 函数可以重复执行某一部分代码(通过函数名调用)
- 使程序变得更简短而清晰
- 有利于程序维护
- 什么时候需要函数
- 当相同的代码出现多次时
- 当需要提取公共代码时
封装:1-100随机数,把重复性的代码写到函数中
<script>
/*
封装:1-100随机数
把重复性的代码写到函数中
* Math.random();//0-1(不等于1)
*/
function randomNumber(){
var number = parseInt(Math.random()*100)+1;
console.log(number);
}
// var number1 = parseInt(Math.random()*100)+1;
// var number2 = parseInt(Math.random()*100)+1;
// 函数的执行
// 格式:函数名()
randomNumber();
randomNumber();
randomNumber();
randomNumber();
</script>
函数的声明
- 仅仅是将函数保存到内存中
- 函数声明注意事项:
- 避免与变量重名
- 声明提前
- 浏览器在逐行解析代码前,会把变量声明和函数声明事先保存在内存中
- 函数声明
- 变量声明(变量声明但不赋值,默认值为undefined)
函数的定义
- 关键字声明(声明式)
函数的声明会提前 ==> 解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);
//格式:funtion 函数名(){}
function show(){}
- 函数表达式(赋值式)
//show();不能这样写
//格式:
var show = function(){}
show();
/*不能在赋值式之前使用show(),show()在前面时只声明了show(相当于var show;)但是show未被赋值此时show的值为undefined,undefined()不是一个函数会报show is not a function错*/
报错会阻止代码向下执行
* 浏览器解析代码步骤
1. 把变量声明和函数声明事先保存到内存中
2. 逐行执行代码* show2 is not a function * 单词写错 * show2不是一个函数
函数的执行
1.手动调用sum();
2.事件驱动:
格式:元素.事件 = 函数名;
btn.onclick = sum;
常见事件触发函数
- onclick:点击事件
- ondblclick:双击事件
- onmouseover:鼠标移入事件
- onmouseout:鼠标移开事件
- onchange:内容改变事件(一般用于表单元素)
- onkeyup:键盘按键弹起事件
页面加载事件:页面<所有内容>加载完毕后执行(元素、图片、视频、音频..)
console.log(111);
window.onload = function(){
console.log(666)
}
console.log(123);
控制台打印效果是111 123 666
变量的作用域
俗称使用范围,变量能够使用的范围,分<全局作用域>和<局部作用域>
- 全局作用域
- 在全局作用域中定义的变量称为全局变量
- 局部作用域
- 在局部作用域下定义的变量称为局部变量(函数内定义的变量是局部变量)
- 变量查找规则
- 就近原则(如查找变量a)
- 使用变量a时先从当前函数查找,如果当前函数有变量a则使用;
- 如果当前函数无变量a,则往父级函数查找,如果找到则使用,并停止查找;
- 如果在父级函数还是无法找到,则继续往上一层函数查找,以此类推,直到最顶层(全局作用域),如果还是没找到,则报not defined错误;
- 就近原则(如查找变量a)
var className = 'h5_1704';
windows.onload = function(){
var myName = 'emon';
//声明函数
function showMsg(){
var myAge = 22;
document.write('大家好,我叫' + 'myname' + '今年'+myAge+'岁,我在' + className)
}
//调用函数
showMsg();
//在函数外使用函数内的变量会报错
console.log('myName');
//console.log('myAge');
}
- 作用域链:每个函数在定义时就形成了局部作用域,如果存在多个函数嵌套,他们之间就会建立起某种联系,直到全局作用域,这种联系称之为作用域链。当函数访问变量时,根据就近原则在这个作用域中从内到外查询变量。
声明提前
- 函数声明提前
变量声明提前
> 声明但没有赋值的变量默认为undefined
、
/*声明提前
提前到当前作用域顶部
*/
var num = 10;
function sum(){
//var num;
console.log(num);//输出的结果是undefined
var num = 30;
}
函数的参数
- 函数的参数:局部变量
- 形参和实参的区别:
- 形参:声明函数时圆括号定义的变量
- 实参:函数执行时传入的函数
形参和实参的数量可以不同
- arguments
函数内部隐藏的对象(是一个类数组),保存这实参的信息
- length:实参的数量
- callee:对函数本身的引用
- 引用数据类型与基本数据类型的传参(引用传递与值传递)
- 函数作为参数传递
<title>封装一个函数,计算所有传入参数的和</title>
<script>
/*
数组:可以保存多个数据的变量
格式:var arr = [10,20,30]
* 索引:标识某个数据的位置
* 索引值从0开始
* 读取:arr[索引值]
* length:表示数组的长度
*/
var arr = [10,20,30];
//console.log(arr[2])
// 函数内部隐藏的对象(是一个类数组),保存着实参的信息
function sum(){
// console.log(arguments);
// var res = num1 + num2;
// console.log(res);
// 存放结果
var res = 0;
// 循环
for(var i=0;i<arguments.length;i++){
res += arguments[i]
}
console.log(res);
}
// sum(10,20);
// sum(12,11);
// sum(1,2,3);
sum(1,2,3,4,5,6,7,8,9);
</script>
函数中的this
函数中的this是一个关键字,表示当前对象,而当前对象是谁取决于谁调用了这个函数
<script>
window.onload = function(){
//这里的this是window
function showMsg(){
//这里的this指向的是window
console.log(window);
}
showMsg();
}
</script>
函数递归
函数可以自己调用自己,成为函数的递归调用。(要避免死循环)
递归调用的过程:
1.首先去找临界值,即无需计算就获得的值(一般返回该值)
2.找这一次和上一次的关系(一般从后往前找)
3.假设当前函数已经可以使用,调用自身计算上一次的运行结果,再写出这次的运行结果
例1:求任意数字的阶乘
function factorial(n){
if(n==1){
return 1;
}
return n*factorial(--n);
}
例2:递归实现斐波那契数列
function fib(n){
if(n==1 || n==2){
return 1;
}
return fib(n-1)+fib(n-2);
}