学习JS的第五天
一、arguments对象
在调用函数时,浏览器每次都会传递两个隐含的参数
1、函数上下文对象this
2、封装实参的对象arguments (arguments的作用就是封装实参)
-
arguments是一个类数组对象,它可以通过索引(下标)来操作数据,也可以获取长度
-
在调用函数时,所传递的实参会全部保存在arguments里面
-
即使没有形参,也可以使用arguments ,如果需要调取参数,
则使用 (表示第一个参数)arguments[0]、(表示第二个参数)arguments[1]…
例子:console.log() 也是通过()来调用的,所以log也是一个函数。log函数的特点是可以接受一个或者或者多个参数。为什么log函数可以接受一个或者多个参数,内部实现原理就用到了arguments
function getSum(){ var sum = 0; for( var i = 0 ; i<arguments.length ; i++){ sum += arguments[i]; } return sum; } var res = getSum(1,11,22,111); console.log(res);
二、arguments属性
callee------ arguments.callee 它指向当前这个正在执行函数对象
arguments.callee.length表示形参的个数
function f(num){
if(num<1){
return 1;
}else{
return arguments.callee(num-1)*num;
}
}
var res = f(5);
console.log(res);
三、作用域
在js里面有个概念是作用域,作用域,域是范围或者区域,简单来说作用域就是一个东西可以起作用的范围
1、作用域分为全局作用域和局部作用域(也有叫函数作用域)
什么是全局作用域,一个script标记或者一个js文件里面就是全局作用域
什么是局部作用域,一个函数内部就是局部作用域,函数外部就是全局作用域
2、全局变量和局部变量
全局变量可以理解为能够在全局作用域和局部作用域都能使用的变量,即大家都可以访问的一个公共变量
//例如
var a = 10 ;
console.log(a); //10
function fn(){
console.log(a);
}
fn(); //10
局部变量是定义在特定区域的变量,或者说定义在函数内部的变量,函数外部和其他函数无法访问到的变量,只有当前函数能访问和使用的变量(若要访问可通过return返回)。
function fn(){
var a =10;
console.log(a);
}
fn(); //10
console.log(a); // Uncaught ReferenceError: a is not defined
还有两种情况 一种是 写在函数内部的变量,但未使用var关键字声明 , 这种变量是全局变量
function fun(){
b = 10 ;
}
fun(); //10
console.log(b); //10
另一种情况 当函数设置了形参,那么这是定义在函数内部的函数就不是全局变量而是 局部变量
function fun(b){ //这里形参起的作用 == var b
b = 10 ;
}
fun(); //10
console.log(b); //b is not defined
3、作用域链
-
全局作用域我们义称之为0级作用域
-
定义函数开启的作用域就是1级 - 2级 - 3级。。。作用城
-
JavaScript会将这些作用域链接在起形成个链条, 这个链条就是作用域链0–1—2---3—4
4、变量在作用域查找规则
- 先在当前找,找到就使用当前作用域找到的
- 如果当前作用域中没有找到,就去上一级作用域中查找
- 以此类推直到0级为止,如果0级作用域还没找到,就报告错
5、变量的生命周期
-
JavaScript 变量生命周期在它声明时初始化。
-
局部变量在 函数执行完毕 后销毁。
-
全局变量在 页面关闭 后销毁
四、预解析
1、 什么是预解析?
浏览器在执行JS代码的时候会分成两部分操作:预解析以及逐行执行代码。也就是说浏览器不会直接执行代码,而是加工处理之后再执行,这个加工处理的过程,我们就称之为预解析
2、预解析规则 - 变量提升
- 将变量声明和函数声明提升到当前作用域最前面
- 将剩余代码按着书写顺序依次放到后面
3、预解析补充
把一个函数赋值给变量(var声明的), 函数声明不会提升
a();
console.log(a);
var a = function(){
console.log(1);
}
预解析演示
// 0级作用域预解析
var a = 3; // var a ;
function fn(){ // function fn(){
var b = 4; // var b = 4 ;
alert(a); // alert(a);
alert(b); // alert(b);
function me(){ // function{ alert(b); }
alert(b); // me();
} // }
me(); // fn();
} // alert(a);
fn(); // 1级作用预解析
alert(a); // function fn() {
// var b ;
// function{ alert(b); }
// b = 4 ;
// alert(a);
// alert(b);
// me();
// }
五、JS的编译和执行
1、先检查语法错误---语法错误,当前代码段不执行
2、声明提升------变量提升和函数提升,作用域内所有使用var声明的变量和非匿名函数
3、开始编译------逐行执行
六、递归
我们都知道,一个函数可以调用其他函数。如果这个函数在内部调用它自己,那么这个函数就叫递归函数。
特点:
1:在函数里面调用自身。
2:必须有一个明确的递归结束条件,这个称之为递归出口。
3:不确定循环执行的次数。
缺点:使用递归函数一定要注意,处理不当就会进入死循环。在实际使用中,递归函数由于消耗时间比较长(相比for循环和while循环),所以很少使用。
1、求Fibonacci的第n个数 1 1 2 3 5 8 13 21…(该数列中,有n个数字,从第三个数字开始:数值 =前一个数字 + 前面一个数字)即,n=(n-2)+(n-1)
function f1 (n) {
if (n == 1) return 1;
if (n == 2) return 1;
return f1(n-1) + f1(n-2);
}
console.log(f1(7));
2、求n个数的累加
function getSum (n) {
if (n == 1) { return 1;}
return n + getSum(n - 1);
}
console.log(getSum(100));
3、求n的阶乘? n! = n * (n-1) !;
function f(num){
if(num<1){
return 1;
}else{
return f(num-1)*num;
}
}