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函数外也找不到,就会报错/抛出异常。这整个寻找的过程就是作用域链。
如图: