前端学习记录 —— JavaScript(二)
前言
本文主要介绍 JavaScript 数组、函数、预解析内容
一、数组
数组的概念
一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
创建数组的两种方式
1. 利用new 创建数组
var 数组名 = new Array([n]);//[]代表可选 若写n,则代表数组的长度
var arr = new Array();//创建了一个名为 arr 的空数组
2. 利用数组字面量创建数组 []
// 1. 使用数组字面量方式创建空的数组
var 数组名 = [];//若写n,则代表数组的长度
//2. 使用数组字面量方式创建带初始值的数组
//3. 声明数组并赋值称为数组的初始化
var arr =['1','2','3','4'];
var arr2 = ['fan',true,17.5];//数组中可以存放任意类型的数据
3. 访问数组元素
索引(下标):用来访问数组元素的序号。索引从 0 开始
<script>
// 1.数组(Array) :就是一组数据的集合 存储在单个变量下的优雅方式
// 2. 利用new 创建数组
var arr = new Array(); // 创建了一个空的数组
// 3. 利用数组字面量创建数组 []
var arr = []; // 创建了一个空的数组
var arr1 = [1, 2, '老师', true];
// 4. 我们数组里面的数据一定用逗号分隔
// 5. 数组里面的数据 比如1,2, 我们称为数组元素
// 6. 获取数组元素 格式 数组名[索引号] 索引号从 0开始
console.log(arr1);
console.log(arr1[2]); // pink老师
console.log(arr1[3]); // true
var arr2 = ['迪丽热巴', '古丽扎娜', '佟丽丫丫'];
console.log(arr2[0]);
console.log(arr2[1]);
console.log(arr2[2]);
console.log(arr2[3]); // 因为没有这个数组元素 所以输出的结果是 undefined
</script>
4. 遍历数组
数组长度: 数组名.length
求数组[2,6,1,77,52,25,7]中的最大值
<script>
var arr = [2, 6, 1, 77, 52, 25, 7, 99];
var max = arr[0];
for (var i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
console.log('该数组里面的最大值是:' + max);
</script>
5. 新增数组元素
数组[数组.length] = 新数据;
// 1. 数组[数组.length] = 新数据;
arr = [] //arr.length = 0;
for (var i = 0; i < 10; i++) {
arr[arr.length] = '0';
}
console.log(arr);
案例
筛选数组 大于10的元素选出来放到新数组中
注意技巧:
<script>
// 将数组 [2, 0, 6, 1, 77, 0, 52, 0, 25, 7] 中大于等于 10 的元素选出来,放入新数组。
// 1、声明一个新的数组用于存放新数据newArr。
// 2、遍历原来的旧数组, 找出大于等于 10 的元素。
// 3、依次追加给新数组 newArr。
// 方法1
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
var j = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= 10) {
// 新数组索引号应该从0开始 依次递增
newArr[j] = arr[i];
j++;
}
}
console.log(newArr);
// 方法2
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
// 刚开始 newArr.length 就是 0
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= 10) {
// 新数组索引号应该从0开始 依次递增
newArr[newArr.length] = arr[i];
}
}
console.log(newArr);
</script>
JS 中涉及数组的删除元素、翻转等可以使用内置对象的方法实现;详见:
https://blog.csdn.net/weixin_43848614/article/details/122334595
二、函数
1. 自定义函数方式(命名函数)
利用函数关键字 function 自定义函数方法
// 声明定义方式
function fn() {...}
// 调用
fn();
因为有名字,所以也被称为命名函数
调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面
2. 函数表达式方式(匿名函数)
利用函数表达式方式的写法如下:
// 这是函数表达式写法,匿名函数后面跟分号结束
var fn = function(){...};
// 调用的方式,函数调用必须写到函数体下面
fn();
- 因为函数没有名字,所以也被称为匿名函数
- 这个 fn 里面存储的是一个函数
- 函数表达式方式原理跟声明变量方式是一致的
- 函数调用的代码必须写到函数体后面
- 如果函数没有 return ,返回的值是 undefine
- return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准
3. 函数的参数
形参:函数定义时候,传递的参数(实参值传递给形参,不用声明的变量);
实参:函数调用时候,传递的参数
//带参数的函数声明
function 函数名(形参1,形参2,形参3…) {
//函数体
}
// 带参数的函数调用
函数名(实参1,实参2,实参3…);
函数形参和实参数量不匹配时
参数个数 | 说明 |
---|---|
实参个数等于形参个数 | 输出正确结果 |
实参个数多于形参个数 | 只取到形参的个数 |
实参个数小于形参 | 多的形参定义为undefined,结果为NaN |
function getSum(a, b, c) {
return a + b + c;
}
// js中形参的默认值是undefined。
// 调用函数
var n = getSum(1, 2);// n = NaN
var n = getSum(1, 2, 3, 4); //1 + 2 +3 = 6
4. break,continue,return的区别
- break: 结束当前的循环体 (如for、while)
- continue: 跳出本次循环,继续执行下次循环
- return: 不仅可以退出(函数体内)循环,还能够返回return语句中的值,同时还可以结束当前的函数体内的代码
//避免踩坑 return只能结束函数体内的代码
function breakDown() {
for (var i = 0; i < 10; i++) {
if (i == 5) {
return 1;
}
console.log(i);
}
}
breakDown();
//避免踩坑2 函数如果有return 则返回的是 return 后面的值;
// return d,a,b; 返回的是b的值
//如果函数没有 return语句,则返回undefined
5. arguments 的使用
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参
arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点:
- 具有 length 属性;
- 按索引方式储存数据;
- 不具有数组的 push , pop 等方法
<script>
// 利用函数求任意个数的最大值
function getMax() { // arguments = [1,2,3]
var max = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
console.log(getMax(1, 2, 3));
console.log(getMax(1, 2, 3, 4, 5));
console.log(getMax(11, 2, 34, 444, 5, 100));
</script>
三、作用域
- 作用域
一段程序代码中所用到的名字并不总是有效和可靠的,而限定这个名字的可用性代码范围就是这个名字的作用域。
作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
ES6之前作用域有两种 全局作用域和局部作用域(函数作用域)
- 「全局作用域」
作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
- 「局部作用域」
作用于函数内部的代码环境,就是局部作用域。因为跟函数有关系,所以也被称为函数作用域。
- JS没有块级作用域
块作用域由 {} 包括
在其他编程语言,if语句中,循环语句创建的变量,仅仅只能在本if语句,本循环语句中使用,如下👇👇
if(true){
int num = 123;
System.out.print(num); //123
}
System.out.print(num);//报错
以上java代码会报错,因为代码中 {}是一块作用域,其中声明的变量num,在{}之外不能使用,而JavaScript代码则不会报错
Js中没有块级作用域 (在ES6之前); es6 新增作用域
if(true){
var num = 123;
console.log(num); // 123
}
console.log(num);// 123
变量的作用域
全局变量和局部变量的区别:
全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会销毁,因此比较占内存
局部变量:旨在函数内部使用,当其所在的代码块被执行时,才会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间。
作用域链
「作用域链」只要是代码都在一个作用域中,写在函数内部的局部作用域,未卸载仍和行数内部即在全局作用域中;如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域;根据[内部函数可以访问外部函数变量] 的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链。
function f1() {
var num = 123;
function f2() {
var num = 0;
console.log(num); // 站在目标出发,一层一层的往外查找
}
f2();
}
var num = 456;
f1();
运行结果:
0
作用域链:采取就近原则的方式来查找变量最终的值
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); //a的值 4
console.log(b); //b的值 '22'
}
}
}
fn1();
四、JS 预解析
「预解析相关概念」JavaScript代码是由浏览器中的JavaScript解析器来执行的。JavaScript解析器在运行JavaScript代码的时候分为两步:预解析和代码执行。
「预解析」在当前作用域下,JS代码执行之前,浏览器会默认把带有 var 和 function声明的变量在内存中进行提前声明或定义。
「代码执行」从上往下执行JS语句
预解析会把变量和函数的声明在代码执行之前完成,预解析也叫做变量、函数提升。
变量预解析(变量提升)
变量的声明会被提升到当前作用域的最上面,变量的赋值不提升。
console.log(num); // 结果是多少?
var num = 10; // ?
相当于
var num;
console.log(num);// 结果是 undefined //注意: 变量提升只提升声明,不提升赋值。
num = 10;
函数预解析(函数提升)
函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
fn();
function fn() {
console.log('打印');
}
结果: 控制台打印字符串 — “打印”
注意: 函数声明代表函数整体,所以函数提升后,函数名代表整个函数,但是函数并没有被调用!
函数表达式声明函数问题
函数表达式创建函数,会执行变量提升,此时接收函数的变量名无法正确的调用
fn();
var fn = function(){
console.log("想不到吧");
}
结果: 报错提示 “fn is not a function”
解释: 该段代码执行之前,会做变量声明提升,fn 在提升之后的值是 undefined ;而 fn 调用是在 fn 被赋值为函数体之前,此时 fn 的值是 undefined,所以无法被调用。
- 预解析案例1
var num = 10;
fun();
function fun(){
console.log(num);
var num = 20;
}
相当于执行了以下操作 结果打印 undefined
var num;
function fun(){
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
- 预解析案例2
var a = 18;
f1();
function f1(){
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
相当于执行了以下操作 结果为 undefined 9
var a;
function f1(){
var b;
var a;
b = 9;
console.log(a);
console.log(b);
a = '123';
}
a = 18;
f1();
- 预解析案例3
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
相当于执行了以下操作 结果为 9 9 9 9 9 "报错--a is not defined"
function f1() {
var a;
a = b = c = 9;
//相当于 var a = 9; b=9; c=9; b和c 直接赋值,没有var声明,当全局变量看。
// 差异:集体声明 var a = 9,b = 9, c = 9;
console.log(a);
console.log(b);
console.log(c);
}
f1();
console.log(c);
console.log(b);
console.log(a);