【ECMAScript笔记三】数组(创建 提取 长度 翻转)、函数、作用域(局部 全局)、函数预解析

2023-12-18 11:51:12

6 数组

  • 作用: 数组(Array)可以把一组相关的数据一起存放,并提供方便的访问(获取)方式。
  • 概念: 数组是一组数据的集合,其中的每个数据被称作数组元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的方式。

6.1 创建数组

  • new 关键字

    var arr =new Array();   // 创建了一个空的数组
    
  • 数组字面量

    //创建一个空的数组
    var arr=[];
    //创建一个有元素的数组
    var arr=[1, 2, 3, 4]//再数组里面可以放任意的数据类型
    var arr=[1, 2, "3", "张三", true]

6.2 提取数组元素

6.2.1 某元素:数组的索引(下标)
  • 概念: 用来访问数组元素的序号,序号从0开始。
  • 方法:数组名[索引]
var arr=[1,3,5,"张三","李四"]
arr[3]     // 张三
arr[5]     // undefined
6.2.2 全部元素:遍历数组
  • 遍历: 就是把数组中的元素全部访问一次。
  • 注意: i必须从0开始,因为数组索引是从0开始的
var arr = [1, 2, 3, 4, 5];
for (var i = 0; i < 5; i++) {   // i:0 1 2 3 4
    console.log(arr[i]);
}

6.3 数组的长度

arr.length
// 1. 求数组 [2, 6, 1, 7, 4] 里面所有元素的和以及平均值
var arr = [2, 6, 1, 7, 4];
var sum = 0;
var average = 0;
for (var i = 0; i < arr.length; i++) {
    sum += arr[i];  
    // 我们加的是数组元素 arr[i] ,不是计数器 i
}
average = sum / arr.length;
console.log(sum, average);  // 想要输出多个变量,用逗号分隔即可
// 2. 求数组[2,6,1,77,52,25,7]中的最大值
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);    // 99
6.3.1 追加/替换元素 索引
var arr=["red","yellow","blue"];
arr[3]="pink";    
// 后面追加元素 结果为arr=["red","yellow","blue","pink"];
arr[0]="yellow";    
// 替换元素 结果为arr=["yellow","yellow","blue"];
6.3.2 选取元素到新数组 newArr[newArr.length]=arr[i];
// 将 arr=[2,0,6,1,77,0,52,0,25,7] 中大于10的元素单独存在一个数组中
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)
    {
        newArr[newArr.length]=arr[i];    
    }
}
console.log(newArr)
// [77, 52, 25]

6.4 翻转数组

var arr = ['red', 'green', 'blue', 'pink', 'purple', 'hotpink'];
var newArr = [];
for (var i = arr.length - 1; i >= 0; i--) {
    newArr[newArr.length] = arr[i]
}
console.log(newArr);
// ['hotpink', 'purple', 'pink', 'blue', 'green', 'red']

7 函数

  • 概念: 封装了一段可被重复调用执行的代码块。

  • 使用步骤: 1、声明;2、调用

// 声明
function 函数名()   // 函数名一般为动词
{
	// 函数体
}

// 调用,执行代码
函数名();
// 利用函数求1~100的和
function getSum(num1,num2)
{
    var sum = 0;
    for(var i = num1; i <= num2; i++)
    {
        sum += i;
    }
    console.log(sum);
}
getSum(1,100);

7.1 形参与实参

// 声明函数
function 函数名(形参1,形参2...) {    // 形参:形式参数

}

// 执行函数
函数名(实参1,实参2,...);    // 实参:实际参数
  • 函数形参和实参个数不匹配的情况
function getSum(num1,num2)
{
	console.log(num1+num2);
}

// 实参的个数 = 形参的个数
getSum(1,2);    // 3
// 实参的个数 > 形参的个数
getSum(1,2,3);  // 3
// 实参的个数 < 形参的个数
getSum(1);      // NaN (形参不传值会默认为undefined)

7.2 return 语句

我们函数只是实现某种功能,最终的结果需要返回给函数的调用者

function 函数名()
{
	//执行语句
	return 需要返回的结果;
}
function getResult() {
	return 666;
}
getResult();    // getResult() = 666
console.log(getResult())   // 666,需要用console.log()打印函数的返回值

注意:

  • 只要遇到return,就把需要返回的结果返回出来,自动跳出函数

  • return一次只能返回一个值

  • 如果我们想要返回多个值,可以使用数组:return [num1,num2,num3];

  • 函数如果没有return,则返回的是undefined

break,continue,return的区别:

  • break:结束当前的循环体
  • continue:跳出本次循环,继续执行下次循环
  • return:不仅可以跳出函数,还可以返回return语句中的值

7.3 argument使用

所有函数都内置了一个arguments对象,当我们不确定有多少个实参传递的时候,可以用arguments来获取。arguments对象中存储了传递的所有实参。

arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点︰

  • 具有length属性
  • 按照索引方式储存数据
  • 不具有真正数组的push() , pop()等方法
function fn()     // 不写形参
{
	console.log(arguments)}
fn(1,2,3);   // 传几个实参就自动存几个到函数的arguments,此时arguments的值为:[1,2,3]
function fn() {
    for (var i = 0; i < arguments.length; i++) {
		console.log(arguments[i]);
    }
}
fn(1, 23);

/*	1
	2
	3	*/

案例:

// 1. 利用函数求任意个数的最大值
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));
// 3 5 444
// 2. 利用函数翻转任意数组 reverse 翻转
function reverse(arr) {
    var newArr = [];
    for (var i = arr.length - 1; i >= 0; i--) {
        newArr[newArr.length] = arr[i];
    }
	return newArr;
}
var arr1 = reverse([1, 3, 4, 6, 9]);
console.log(arr1);
var arr2 = reverse(['red', 'pink', 'blue']);
console.log(arr2);

7.4 函数相互调用

// 用户输入年份,输出当前年份2月份的天数
function backDay() {
    var year = prompt('请您输入年份:');
    if (isRunYear(year)) {
		alert('当前年份是闰年2月份有29天');
	} 
    else {
		alert('当前年份是平年2月份有28天');
	}
}
backDay();

// 判断是否为闰年的函数
function isRunYear(year) {
	// 如果是闰年我们返回true,否则返回false 
	var flag = false;
    if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
    	flag = true;
	}
	return flag;
}

7.5 声明函数的方式

  • 用函数关键字自定义函数(命名函数):
function fn() {

}
fn();
  • 函数表达式(匿名函数):
var 变量名 = function(形参) {

}
fn();   // 调用函数的方法一样,使用`fun(实参)`

8 作用域

概念: 代码名字(变量)的作用范围

目的: 提高程序的可靠性,减少命名冲突

分类: 全局作用域、局部作用域(es6之前)

  • 全局作用域:整个script标签 / 一个单独的js文件

    <script>
        var num=10;
    </script>
    
  • 局部作用域:函数内部

    function fun()
    {
    	var num=10;
    }
    

8.1 全局变量和局部变量

  • 全局变量: 全局作用域 下的变量

  • 局部变量: 局部作用域 下的变量

function fun(aru)   // 该形参也是局部变量,外部无法调用
{
	var num1 = 10;  // num1为局部变量
	num2 = 20;   // num2为全局变量(没有声明,直接赋值),不建议使用
}

注意:

  • 全局变量:浏览器关闭的时候才会销毁,占内存资源

  • 局部变量:程序执行完毕就会销毁,节约资源

8.2 作用域链

作用域链:内部函数访问外部函数的变量,采用链式查找(从内层到外层,一层一层地往外查找)的方式确定取值,采用就近原则。

function fun1()
{
    var num=10;
    function fun2()
    {
        var num=20;
        function fun3()
        {
            console.log(num);   // 20(就近原则)
        }
    }
}
  • num=20相对于fun3是全局变量,但相对于fun1是局部变量,不可调用
  • num=10相对于fun2fun3都是全局变量,可调用

9 函数预解析

为什么会出现以下情况:

console.log(num);
var num = 10;
// undefined
fun();    // 先调用也没事
function fun()
{
	console.log(11);
}
// 11
fun();
var fun = function()
{
	console.log(22);
}
//  报错
  1. JS引擎运行JS分为以下两步:

    • 预解析: JS会把JS里面所有的 var变量function函数 放到当前作用域的最前面
    • 代码执行: 按照代码书写的顺序从上到下执行
  2. 预解析分为以下两步:

    • 变量预解析(变量提前): 把所有的变量声明提到当前的作用域最前面,不提赋值操作

      console.log(num);
      var num=10;   // undefined
      
      // 实际预解析步骤如下:
      var num;      // 把var提到`当前的作用域`最前面
      console.log(num);
      num = 10;     // 不提`赋值操作`,结果为undefined
      
      fun();
      var fun=function() {
      	console.log(22);
      }     //  报错
      
      // 实际预解析步骤如下:
      var fun;   // 把var提前
      fun();   // 未定义函数,报错
      fun=function() {
      	console.log(22);
      }
      
    • 函数预解析(函数提前): 把所有的函数声明提升到当前作用域的最前面,不调用函数

      fun();    // 先写也没事儿,只是位置提前,实际没有被调用
      function fun()  {
      	console.log(11);
      }   // 11
      
      // 实际预解析步骤如下:
      function fun()  {  // JS会自动把函数声明部分提前
      	console.log(11);
      }
      fun();    // 再调用,结果为11
      

预解析案例:

// 案例1
var num = 10;
fun();
function fun() {
    console.log(num);
    var num = 20;
}

// 相当于执行了以下操作
var num;
function fun() {
    var num;     // var提升到当前作用域
    console.log(num);
    num = 20;
}
num = 10;   // 剩余的函数从上往下依次写下来
fun();
// 结果:undefined
// 案例2
var num = 10;
function fn() {
    console.log(num);
    var num = 20;
    console.log(num);
}
fn();

// 相当于以下代码
var num;
function fn() {
    var num;
    console.log(num);
    num = 20;
    console.log(num);
}
num = 10;
fn();
// 结果:undefined 20
// 案例3
var a = 18;
f1();
function f1() {
    var b = 9;
    console.log(a);
    console.log(b);
    var a = '123';
}

// 相当于以下代码
var a;
function f1() {
    var b;
    var a;
    b = 9;
    console.log(a);   // a取值应该往上找
    console.log(b);
    a = '123';
}
a = 18;
f1();
// 结果:undefined 9
// 案例4
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);
}

// 相当于以下代码
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); // 函数内部定义的变量为局部变量,不可调用
// 结果:9 9 9 9 9 报错

文章来源:https://blog.csdn.net/waski/article/details/135009028
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。