前端~javascript~JS数组/函数function/作用域/作用域链/向上查找

JS数组

在Java/C中,要求数组中的变量是相同类型的。但在JS中不要求,因为JS是动态类型语言,同理,在其他动态类型语言中(如Python,PHP),都不要求。
创建数组的方式
1.通过new关键字来创建(类似Java)

<body>
 var arr=new Array();
</body>

在JS中,数组也是一个“对象”

2.通过字面量的方式创建(常用)

<script>
    var arr=[];
    //JS中通过[] 表示数组~
    var arr2=[1,2,3,4,'haha',false];
</script>

从上面代码可知,JS中的数组并不要求元素是相同类型。

获取数组元素
使用下标访问数组

<script>
    let arr=['小猪佩奇','小羊苏西','小猫凯迪','小兔瑞贝卡'];
    console.log(arr[0]);
    console.log(arr[1]);
    console.log(arr);
    arr[2]='小狗丹妮';
    console.log(arr);
</script>

在这里插入图片描述
在JS数组中,尝试读取数组中不存在的下标,就会出现undefined这样的结果。

console.log(arr[7]);   // undefined
console.log(arr[-1]);  // undefined

但如果尝试往JS数组中写入不存在的下标,就会往这个下标插入元素,同时可能会修改数组的长度。虽然数组长度发生了变化,但中间元素的值,任然没有定义,仍然是undefined.

<script>
    let arr=[];
    arr['hello']='world';
    
    console.log(arr['hello']);//world
    console.log(arr); //[hello='world']
</script>

JS可以给数组指定一个字符串 类型的“下标”。此处这个"下标"更应该理解成是“属性”,也就相当于“键值对”。
JS数组是一个对象,对象是可以在运行时动态的 新增或者删除属性

举个例子。如下是Test类, num是其属性, JS可以在运行中给Test类新增加一个属性,或者删除num属性!
class Test{
int num;
}

也就是说,下面两行代码等价

arr['hello']='world';
arr.hello='world';

第一种写法看起来是在操作下标,实际上是在给arr创建一个hello属性,因为前面说过,在JS中,数组可以看成是对象

新增数组元素

  • 通过下标新增
    在JS中,我们可以直接通过下标向数组中添加元素,如果下标超出数组范围,则会在指定的下标位置插入新元素。
var arr=[];
arr[2]=10;
console.log(arr);
  • push添加

JS数组可以看成一个对象,有属性和方法,上面介绍了设置字符串属性,这里介绍添加方法push.

代码演示:

<script>
    var arr=[9,5,2,7,3,6,8];
    var newArr=[];
    for(var i=0;i<arr.length;i++){
        if(arr[i]%2 !=0){
            newArr.push(arr[i]);
        }
    }
    console.log(newArr);
</script>

输出:
在这里插入图片描述
删除数组元素
通过splice方法删除元素

<script>
    var arr=[9,5,2,7,3,6,8];
    var newArr=[];
    for(var i=0;i<arr.length;i++){
        if(arr[i]%2 !=0){
            newArr.push(arr[i]);
        }
    }
    console.log(newArr);

    newArr.splice(2,3); //[9,5,7,3]
</script>

JS还有很多的 属性和方法,这里只是简单介绍了几种常用的,如果想了解更多的属性和方法,可以查看下面的文档。
MDN文档

函数

语法格式
JavaScript函数通过function关键词进行定义,其后是函数名和括号()。

function 函数名(参数列表){
函数体
return 返回值;
}

函数定义后并不会执行函数体内容,必须要调用才会执行,调用几次就执行几次。

<script>
    //函数的定义
   function hello() {
       console.log("hello");
   }
   
   //函数执行
    hello();
    
</script>

函数的位置与调用的先后顺序无关,写在调用位置前后都可以。(与C不同, C语言函数必须写在调用之前,否则就要声明。)

函数参数个数

实参和形参的个数可以不匹配,但是实际开发时一般要求匹配。

1.如果实际参数个数比形式参数个数多,则多出来的参数不参与函数运算。

<script>
    //函数的定义
   function sum(x,y) {
       console.log(x+y);
   }

   //函数执行
    sum(10,10,30);    //20

</script>

2.如果实际参数个数比形式参数个数少,则多出来的形式参数值为undefined.

<script>
    //函数的定义
   function sum(x,y) {
       console.log(x+y);
   }

   //函数执行
    sum(10);    //NaN
</script>

正因为JS这里的参数设定非常灵活,因此JS根本不需要“函数重载”这样的语法~

<script>
    function add(a,b,c) {
        a=a || 0;
        b=b || 0;
        c=c || 0;

        return a+b+c;
    }

    console.log(add(10));     //10
    console.log(add(10,20));   //30
    console.log(add(10,20,30));  //60
    console.log(add(10,20,30,40));  //60

</script>

函数表达式

<script>
    //定义了一个函数addFunc 然后把这个函数赋值了一个变量
    let add=function  addFunc ( a,b,c,d) {
        a=a || 0;
        b=b || 0;
        c=c || 0;
        d=d || 0;
        return a+b+c+d;
    }
    console.log(add(10));     //10
    console.log(add(10,20));   //30
    console.log(add(10,20,30));  //60
    console.log(add(10,20,30,40));  //60
</script>

在上面的代码中,我们定义了函数addFunc,然后将其赋值给一个变量。这种写法在Java中不存在,因为Java中的函数不能独立存在。
在Js中,函数和一个普通 的变量相似,可以相互赋值,也可以作为另一个函数的参数,还可以作为另一个函数的返回值~

上面的代码中,赋值之后,addFunc函数名可以省略,函数完全可以用add进行替代。这就相当于定义了一个匿名(没有函数名)函数,把这个函数值赋值给了另外一个变量~此时就可以直接调用这个变量。

不定义函数名 的函数,一般称为“匿名函数”,也可以叫做“lambda表达式”. Java中也有lambda表达式,也是为了表达类似的效果,但受限于Java语法本身,函数不能独立~,因此Java的lambda 严格的说不能算是一个匿名函数,只能算是一个“函数式接口”的对象。

作用域

作用域即某个标识符名字在代码中的有效范围
在ES6标准之前,作用域主要有两个:

  • 全局作用域:在整个script标签中,或者单独的js文件中生效。
  • 局部作用域/函数作用域:在函数内部生效。

关于变量的作用域,不同的定义变量的方式,有区别
var定义的变量,没有块级作用域,而let 定义的变量,有块级作用域~(代码块级别的,{}限制作用域)

注意:后面讨论的作用域,都只是讨论let的作用域。

<script>
// 全局变量
var num = 10;
console.log(num);
function test() {
    var num = 20;
    console.log(num);
}
function test2() {
    // 局部变量
    var num = 30;
    console.log(num);
}
test();
test2();
console.log(num);
</script>

作用域链

当一个内部函数访问外部函数的变量时,采取的是链式查找的方式,从内到外依次进行查找。

这有两个前提/背景:

  • 函数可以定义在函数内部
  • 内层函数可以访问外层函数的局部变量
<script>
    let num=1;
    function testFunc1() {
        let num=10;
        function testFunc2() {
            let num=20;
            console.log(20);
        }
        testFunc2();
    }
    testFunc1();      //输出 20
</script>

执行 testFunc1时,会进入到内部函数testFunc2,当testFunc2要打印num时,会先在testFunc2函数中寻找,如果找不到,就会向上寻找,即进入testFunc1内部寻找,如果此时也找不到,就会再向上寻找,如果testFunc1函数外也找不到,就会报错/抛出异常。这整个寻找的过程就是作用域链
如图:
在这里插入图片描述

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值