作用域、回调函数、递归与数组的创建

一、作用域

作用域,就是一个变量可以生效的范围。

变量不是在所有地方都可以使用的,而这个变量的使用范围就是作用域。

1、全局作用域

全局作用域是最大的作用域

  • 在全局作用域中定义的变量可以在任何地方使用
  • 页面打开的时候,浏览器会自动给我们生成一个全局作用域 window
  • 全局变量可以用来存储数据,这个作用域会一直存在,直到页面关闭就销毁了

2、局部作用域

局部作用域就是在全局作用域下面有开辟出来的一个相对小一些的作用域

  • 在局部作用域中定义的变量只能在这个局部作用域内部使用。而在 JS 中只有函数能生成一个局部作用域,别的都不行

  • 每一个函数,都是一个局部作用域。

    在函数中使用var定义的变量一定是局部变量,参数也是局部变量。(早期的原生js不需要使用var就可以定义变量,认为它是window变量,所有的变量都是window的属性而window是可以省略的。但到了ES5后面,严格要求代码不允许无声明就使用变量)

   function abc(){
       //这里的a是全局变量
       a=1;
   }
  • 定义的局部变量不会改变全局变量。

  • 局部变量的优先级高于全局变量。

    一旦在函数中定义了局部变量,这个局部变量名字如果和全局变量名字相同,全局变量将无法直接在函数中使用了
    若要在函数中调用全局变量,则要使用window.全局变量。但在ES6中也不允许使用了

    var a=3;
    function abc(a){
        //参数是局部变量,虽然没有使用var,但是一旦确定为参数,就相当于定义了一个局部变量var a
        console.log(a);//10
        a++;
    }
    abc(10);
    console.log(a);//3
    
    var obj={a:1};
    function abc(o){
        //没有改变局部变量
        o.a=10;
        //这里才是真正更改局部变量,更改变量的引用地址
        // o={a:10};
    }
    abc(obj);
    console.log(obj.a);//第一种情况是10,第二种情况是1
    
    var a=1;
    //全局变量变量a覆盖全局函数a 
    function a(a){
        console.log(a);
        var a=3;
        console.log(a);
    }
    console.log(a);//1
    a(10);//1不是一个函数,所以报错
    console.log(a);
    
    
    
    【注】var a;是undefined,如果a原来有值,就保持原值
    【注】var a=undeifned;也是undefined,未定义,有值,值是undefined
    var a;
    function a(a){
        console.log(a);
        var a=3;
        console.log(a);
    }
    console.log(a);//打印这个函数
    a(10);//10   3
    a=1;//会将函数a覆盖,变成全局变量a=1
    console.log(a);//1
    
  • 局部变量一般都是临时变量,执行完成后就会被销毁

【注】能用局部变量解决就尽量不要用全局变量

二、回调函数与递归

1、回调函数

function abc(fn){
    // fn就是回调函数
    fn(3,5);
}
function getSum(a,b){
    console.log(a+b);
}
abc(getSum);

回调函数可以应用在某个事件完成或者某个时间达到再去执行函数

时间间隔方法(定时器,单位是毫秒ms)

setInterval(执行函数,间隔多长时间执行一次){}

【例】

var i=0;
//时间间隔方法,每间隔1000毫秒执行一次方法,
//在这里animation函数就是回调函数,每间隔1000毫秒回调执行一次这个函数
var ids=setInterval(animation,1000);
//返回一个值,这个值就是当前定时器的标识id
function animation(){
    i++;
    console.log(i);
    if(i>10){
    // clearInterval清除定时器,ids就是刚才设置定时器时的返回标识id
       clearInterval(ids);
    }
}

2、递归函数

在编程世界里面,递归就是一个自己调用自己的手段。
递归函数:一个函数内部,调用了自己,循环往复

// 下面这个代码就是一个最简单的递归函数
// 在函数内部调用了自己,函数一执行,就调用自己一次,在调用再执行,循环往复,没有止境
function fn() {
  fn();
}
fn();
  • 其实递归函数和循环很类似.需要有初始化,自增,执行代码,条件判断的,不然就是一个没有尽头的递归函数,我们叫做 死递归

  • 递归如果没有限制的话,就会造成堆栈上线溢出

  • 当希望遍历具备有深度数据结构时,通常使用递归或者while更方便

  • 当希望遍历具备有广度数据结构时,一般使用for循环遍历

递归案例1:

var i=1;
function abc(){
   i++;
   if(i>3) return;
   abc();
   console.log(i);//结果是打印了2次4
}

abc();
//上述程序的执行过程:
调用函数abc,进入函数内部。
(1)全局变量i初值为1,执行i++,i变成2,
(2)此时i的值不满足i>3的条件,所以不执行if语句;
(3)调用自己,即在栈中复制了自己,形成了一个副本1。接下来先执行副本中的内容,再执行最后一句输出i的值。
function abc(){
   i++;
   if(i>3) return;
   abc();
   console.log(i);
}
(4)上次得到的i值是2,执行i++后i值变为3;
(5)此时i的值不满足i>3的条件,所以不执行if语句;
(6)调用自己,即在栈中复制了自己,形成了一个副本2。接下来先执行副本中的内容,再执行最后一句输出i的值。
function abc(){
   i++;
   if(i>3) return;
   abc();
   console.log(i);
}
(7)上次得到的i值是3,执行i++后i值变为4;
(8)此时i的值满足i>3的条件,执行return(return后面的语句将执行不到),返回到副本1中,同时删除副本2。
(9)回到副本1中,执行上次未执行的输出i,值为4。由于执行结束,则回到原函数中,同时删除副本1。
(10)回到原函数中,执行上次未执行的输出i,值依然为4。函数执行完成!

递归案例2:

 var obj={
        a:{
            a:{
                a:{
                    a:{
                        a:null,
                        value:5
                    },
                    value:4
                },
                value:3
            },
            value:2
        },
        value:1
    };

    // 满足条件进入递归
 function showObj(o){
    console.log(o.value);//输出结果是1 2 3 4 5
    if(o.a) showObj(o.a);
 }

 showObj(obj);
//上面这段程序的执行过程:
  (1)将对象obj带入函数中的参数o,输出obj的value属性的值1。
  (2)判断obj的a属性的值是否存在?存在的,那么就调用自己,生成自己的一个副本1:
  function showObj(o){
    console.log(o.value);
    if(o.a) showObj(o.a);
 }
  将obj.a(如下所示)带入:
            a:{
                a:{
                    a:{
                        a:null,
                        value:5
                    },
                    value:4
                },
                value:3
            },
            value:2
  (3)将obj.a带入o之后,输出obj.a的value属性的值2。
  (4)判断obj.a的a属性的值是否存在?存在的,那么就调用自己,生成自己的一个副本2:
  function showObj(o){
    console.log(o.value);
    if(o.a) showObj(o.a);
 }
  将obj.a.a(如下所示)带入:
            a:{
                a:{
                     a:null,
                    value:5
                 },
                value:4
            },
            value:3
  (5)将obj.a.a带入o之后,输出obj.a.a的value属性的值3。
  (6)判断obj.a.a的a属性的值是否存在?存在的,那么就调用自己,生成自己的一个副本3:
  function showObj(o){
    console.log(o.value);
    if(o.a) showObj(o.a);
 }
  将obj.a.a.a(如下所示)带入:
            a:{
                a:null,
                value:5
              },
            value:4
  (7)将obj.a.a.a带入o之后,输出obj.a.a.a的value属性的值4。
  (8)判断obj.a.a.a的a属性的值是否存在?存在的,那么就调用自己,生成自己的一个副本4:
  function showObj(o){
    console.log(o.value);
    if(o.a) showObj(o.a);
 }
  将obj.a.a.a.a(如下所示)带入:
            a:null,
            value:5
  (9)将obj.a.a.a.a带入o之后,输出obj.a.a.a.a的value属性的值5。
  (10)判断obj.a.a.a.a的a属性的值是否存在?不存在,函数完成

三、数组

1、数组的含义

数组中的每个数据都使用逗号分隔,数据可以是任何类型,数据顺序排列,可以重复。

  • 数组和对象一样都是引用数据类型
  • 数组中的数据按照顺序排列,从0开始,把这个叫做索引或者下标。把数组中的每个数据叫做元素或者简称元。
    例如arr[0]=3;这里的0叫做下标,3叫做元素,arr[0]叫做下标变量

2、数组的创建

(1)字面量创建

var arr=[2,3,4,6,2,1];

(2)构造函数创建

var arr=new Array(2,3,4,6,2,1);

使用构造函数创建数组时,若参数只有一个,则:

  • 如果这个参数是正整数,则表示新建一个具备该正整数长度(元素的个数)的空数组,里面有这个长度的空元素,如var arr1=new Array(5);
  • 如果这个参数是负数或者小数,就会报错。如var arr2=new Array(2.5);
  • 如果这个参数不是数值,而是其他类型时,这个数据就会作为该数组的第0个元素,长度为1,如var arr3=new Array(“a”);

3、数组长度

数组的长度是指元素的个数,用 数组名.length获取。

  • 由于数组下标从0开始,数组的最大下标是数组长度-1
arr[arr.length-1]=10;把数组最后一个元素赋值为10
arr[arr.length]=20;在数组的最尾部再添加一个元素
  • 数组的长度是可以被修改的
var arr[1,2,3,4,5];
arr.length=3;//修改数组的长度为3,剩下的元素被删除
arr.length--;//表示删除最后一个元素
arr.length=0;//清空整个数组
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值