web.jpeg
函数
函数声明
- 函数:一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值。
- 格式如下:
function 函数名字( 参数1,参数2){ 执行语句 }
调用:函数名称()
- 命名规范:
只能是字母、数字、下划线、美元符号,不能以数字开头
。
<script type="text/javascript">
//调用函数
sayHello();
//声明函数
function sayHello() {
console.log("您好。欢迎您")
}
</script>
函数表达式
- 除了
function 声明
函数意外,还可以使用变量
赋值的写法命名函数,我们称为函数表达式(其本质
就是将一个匿名函数
赋值给一个变量
) - 在语句结束的时候必须 要有
分号 ;
<script type="text/javascript">
//匿名函数
function () {
console.log("这是一个匿名函数");
}
//赋值给变量--> 函数表达式
var fuc = function (a) {
console.log(a)
};
fuc("哈哈")
</script>
函数的参数 和 返回值
参数
-
arguments
是存储了函数传送过来实参 ,是一个伪数组
; - Javascript在创建函数的同时,会在函数内部创建一个
arguments对象实例
. -
arguments对象
只有函数开始时才可用。函数的 arguments 对象并不是一个数组,访问单个参数的方式与访问数组元素的方式相同 -
arguments
对象的长度是由实参
个数而不是形参个数决定的
<script type="text/javascript">
sayHello("你是?","哈哈");
function sayHello(a,b) {
console.log(arguments.length);
console.log(a + b)
}
</script>
//打印结果:
2
你是?哈哈
- 函数作为
参数
,这个参数(函数)可以叫做回调函数
<script>
//
function f1(fn){
fn();
}
function f2(){
console.log("开始使用");
}
// f2是函数的代码
f1(f2);
//打印结果: 开始使用
var arr = [10,200,30,110,40,20,50,200];
//函数作为参数
arr.sort(function(obj1,obj2){
if(obj1 > obj2) {
return 1;
} else if (obj1 == obj2){
return 0;
} else {
return -1;
}
});
console.log(arr); // [10, 20, 30, 40, 50, 110, 200, 200]
</script>
返回值
//返回值
var c = sum(10,20);
console.log(c)
//打印结果: 30
//定义函数
function sum(num1,num2) {
return num1 + num2
}
- 函数可以作为返回值 返回
//函数作为返回值
function f3(){
return function(){
console.log("回一个函数");
}
}
let fs = f3(); //此时fs是函数代码
fs();
//执行结果数输入: 回一个函数
-
函数作为返回值和参数的例子
//文件对象构造函数
function File(name, size, time) {
this.name = name;
this.size = size;
this.time = time;
}
//文件对象
var f1 = new File("jack.avi", "400M", "1997-12-12");
var f2 = new File("tom.avi", "200M", "2000-12-12");
var f3 = new File("haungfeihong.avi", "800M", "2017-12-12");
//数组
var arr = [f1, f2, f3];
//文件排序 对象是不能让你更排序的 只有里面的属性才可以
function fileSort(attr) {
//函数作为返回值
return function (obj1, obj2) {
if (obj1[attr] > obj2[attr]) {
return 1;
} else if (obj1[attr] == obj2[attr]) {
return 0;
} else {
return -1;
}
}
}
//排序 函数作为参数 fileSort 返回的是一个函数
arr.sort(fileSort("size"));
console.log(arr);
作用域(变量的使用范围)
-
全局变量:声明的变量是使用
var
声明的,那么这个变量就是全局变量,全局变量可以在页面的任何位置使用- 除了函数以外,其他的任何位置定义的变量都是全局变量
全局作用域:全局变量的使用范围
局部变量:在
函数内部
定义的变量,是局部变量,外面不能使用局部作用域:
局部变量的使用范围
隐式全局变量:
声明的变量没有var
,就叫隐式全局变量
function fn () {
//隐式全局变量
num = 100;
};
fn(); //调用
console.log(num);
作用域链(搜索机制:内部开始搜索,找不到,在去外部搜索,就近原则)
作用域链.jpg
- 如上图一样,在调用f1函数时, 输入函数 log在寻找num的变量时,是从函数
内部
,也是上3级作用开始 向外部
寻找,如果在内部或者3级作用域
找到num
就输入,如果3及作用域没有,就向上一个作用域寻找,一直把所有的作用域找完,没有就报错。
预解析(浏览器解析代码前,把变量的声明和函数的声明
提升到作用域的最上面)
js
的执行过程是 1.先对代码编译 2.预解析 3.执行代码
变量名的提升
<script>
console.log(num);
var num = 10;
//打印结果: undefined
</script>
- 案例说明,变量在声明的时候,
变量明提升到头部了
,
var num;
console.log(num);
num = 10;
//打印结果: undefined
函数名的提升
- JavaScript 引擎将函数名视同
变量名
,所以采用function命令声明函数时,整个函数会像变量声明一样
,被提升到代码头部
<script type="text/javascript">
f1();
function f1 () {
console.log("看看");
}
</script>
模拟预解析
//模拟提升
//与解析 提升函数代码块
function f1 () {
console.log("看看");
}
//执行
f1();
- 预解析会分段(多对的script标签之间函数重名没有影响)
// script标签1
<script type="text/javascript">
f1();
function f1 () {
console.log("看看");
}
//模拟提升
//与解析 提升函数代码块
function f1 () {
console.log("看看");
}
//执行
f1();
</script>
// script标签2
<script type="text/javascript">
f1();
function f1 () {
console.log("这还是");
}
</script>
- 注意:
如果采用赋值语句定义函数,变量提升后,在运行的时候JavaScript 就会报错(函数表达式)
//变量提升 没有问题
f();
function f() {}
// 变量提升 有问题
f1();
var f1 = function (){};
// TypeError: undefined is not a function
//解释
//预解析
var f1;
f1(); //报错
f1= function (){};
- 在函数体内部,声明变量,会把该声明提升到函数体的最顶端。 只提升变量声明,不赋值。
<script type="text/javascript">
var num = 10;
func();
function func() {
console.log(num);
var num = 20;
}
</script>
//结果是: undefined
相当于这样的代码
<script type="text/javascript">
var num = 10;
func();
function func() {
//变量提升到头部
var num;
//log函数会在 这个作用域里面寻找num, 作用域链
console.log(num);
num = 20;
}
</script>
- 注意:全局隐式函数
f1();
console.log(c);//9
console.log(b);//9
console.log(a); //报错
function f1 () {
var a = b = c = 9; //b,c是隐式函数 全局
console.log(a); // 9
console.log(b); //9
console.log(c);//9
}
//预解析 函数代码块 提升
function f1 () {
//a是 函数体内的局部变量
// 预解析 提升a 在函数体的作用域内
var a;
a = 9;
//解释 函数f1内部的变量 只有 a是var声明的 局部变量 b和c是隐式全局变量
b = 9;
c = 9;
console.log(a); // 9
console.log(b); //9
console.log(c);//9
}
//调用函数
f1()
console.log(c);//9
console.log(b);//9
console.log(a); //报错
注意
- 在
与解析阶段
会对var 声明的变量 和 function 声明的代码块进行声明 提升
,提升到当前作用域
的顶端
2.变量和变量同名 后面会覆盖前面的
3.函数和函数同名 后面的会覆盖前面的
4.变量和函数同名只提升函数的声明
,不提升和函数同名的变量
function test(a) {
console.log(a);
var a = 10;
console.log(a);
function a() {
}
console.log(b);
var b = function () {
};
console.log(b);
}
test(1);
打印结果
分析
function test(a) {
//预解析 函数 被提升到顶端
// 注意a 有函数 有变量的时候 只提升函数的声明
function a() {
}
//预解析 变量 被提升到 作用域的顶端
var b;
//当执行 下面的代码的时候
console.log(a); // 打印 函数体
var a = 10;
console.log(a); //打印是 10
console.log(b); //打印是 undefined
var b = function () {
};
console.log(b); // 打印是 函数体
}
函数递归
- 函数中调用函数自己,此时就是递归,递归一定要有结束的条件
- 递归求和
//递归求和
function getSum (x) {
//如果 x是1的话 返回1
if (x == 1) {
return 1;
}
return x + getSum(x -1);
}
console.log(getSum(5)); ===》 15
递归.jpeg
- 每个数字之和 比如:123 1+2+3 = 6
//求出个位数 然后相加
function getEverySum (x) {
if (x < 10) {
return x;
}
//获取这个数字的个位数 一直获取个位 相加
return x%10 + getEverySum(parseInt(x/10));
}
console.log(getEverySum(136));
案例 求输入年月日,计算出是多少天
// 判断是否为闰年
function isLeapYear(year){
return (year % 4 == 0 && year % 100 == 0) || year % 400 == 0
}
//计算
function getDays(year,month,day){
// 存储对应的天数
let days = day;
//是否是一月份
if(month == 1){
return days;
}
//定义 12宇哥 每一个月对应的天数
let months = [31,28,31,30,31,30,31,31,30,31,30,31];
for(let i = 0; i < month - 1; i ++){
days += months[I];
}
//判断是否为闰年
if(isLeapYear(year) && month > 2){
days ++;
}
return days;
}
console.log(getDays(2018,3,2));
// 61