数组、函数、作用域、预解析


一、JavaScript 数组

  • 数组是指一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式。
// 普通变量一次只能存储一个值
let  num = 10; 
// 数组一次可以存储多个值
let arr = ['小白',2,true,4.5];
let arr = [1,2,3,4,5];

1、创建数组

(1)new 创建数组

let arr = new Array(); // 创建了一个空的数组
console.log(arr);

(2)数组字面量创建数组

  • 数组的字面量是方括号 [ ]
  • 声明数组并赋值称为数组的初始化
let arr0 = []; // 创建了一个空的数组
let arr1 = [1, 2, 'pink老师', true]; //创建带初始值的数组
console.log(arr0); 
console.log(arr1);

2、获取数组中的元素

  • 数组可以通过索引来访问、设置、修改对应的数组元素,我们可以通过“数组名[索引]”的形式来获取数组中的元素。
 let arr = ['迪丽热巴', '古丽扎娜', '佟丽丫丫'];
 console.log(arr[0]); //迪丽热巴
 console.log(arr[1]); //古丽扎娜
 console.log(arr[2]); //佟丽丫丫
 console.log(arr[3]); // 因为没有这个数组元素 所以输出的结果是 undefined

3、遍历数组

  • 遍历: 就是把数组中的每个元素从头到尾都访问一次。
  • 我们可以通过 for 循环索引遍历数组中的每一项
 let arr = ['red', 'green', 'blue'];
 for (let i = 0; i < arr.length; i++) {
     console.log(arr[i]);
 }
  • 使用“数组名.length”可以访问数组元素的数量(数组长度)。
  • 此处数组的长度是数组元素的个数 ,不要和数组的索引号混淆。
  • 当我们数组里面的元素个数发生了变化,这个 length 属性跟着一起变化。

案例:
求数组[2,6,1,77,52,25,7]中的最大值

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 求数组[2,6,1,77,52,25,7]中的最大值
        // 声明一个保存最大元素的变量 max。
        // 默认最大值可以取数组中的第一个元素。
        // 遍历这个数组,把里面每个数组元素和 max 相比较。
        // 如果这个数组元素大于max 就把这个数组元素存到 max 里面,否则继续下一轮比较。
        // 最后输出这个 max
        let arr = [2, 6, 1, 77, 52, 25, 7, 99];
        let max = arr[0];
        for (let i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        console.log('该数组里面的最大值是:' + max);
    </script>
</head>

<body>

</body>

</html>

数组转换为分割字符串
要求:将数组 ['red', 'green', 'blue', 'pink'] 转换为字符串,并且用 |其他符号分割
输出: ‘red|green|blue|pink

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 将数组 ['red', 'green', 'blue', 'pink'] 转换为字符串,并且用 | 或其他符号分割
        // 1.需要一个新变量用于存放转换完的字符串 str。
        // 2.遍历原来的数组,分别把里面数据取出来,加到字符串里面。
        // 3.同时在后面多加一个分隔符
        let arr = ['red', 'green', 'blue', 'pink'];
        let str = '';
        let sep = '|';
        for (let i = 0; i < arr.length; i++) {
            str += arr[i] + sep;
        }
        console.log(str);
    </script>
</head>

<body>

</body>

</html>

4、数组中新增元素

(1)通过修改 length 长度新增数组元素

  • 可以通过修改 length 长度来实现数组扩容的目的
  • length 属性是可读写的
let arr = ['red', 'green', 'blue'];
console.log(arr.length); // 3
arr.length = 5; // 把我们数组的长度修改为了 5  里面应该有5个元素 
console.log(arr);
console.log(arr[3]); // undefined
console.log(arr[4]); // undefined
  • 其中索引号是 3,4 的空间没有给值,就是声明变量未给值,默认值就是 undefined

(2)通过修改数组索引新增数组元素

  • 可以通过修改数组索引的方式追加数组元素
  • 不能直接给数组名赋值,否则会覆盖掉以前的数据
let arr1 = ['red', 'green', 'blue'];
arr1[3] = 'pink';
console.log(arr1);
arr1[4] = 'hotpink';
console.log(arr1);
arr1[0] = 'yellow'; // 这里是替换原来的数组元素
console.log(arr1);
arr1 = '有点意思';
console.log(arr1); // 不要直接给 数组名赋值 否则里面的数组元素都没有了

在这里插入图片描述
案例:将数组 [2, 0, 6, 1, 77, 0, 52, 0, 25, 7] 中大于等于 10 的元素选出来,放入新数组

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 将数组 [2, 0, 6, 1, 77, 0, 52, 0, 25, 7] 中大于等于 10 的元素选出来,放入新数组。
        // 1、声明一个新的数组用于存放新数据newArr。
        // 2、遍历原来的旧数组, 找出大于等于 10 的元素。
        // 3、依次追加给新数组 newArr。        
        let arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
        let newArr = [];
        // 刚开始 newArr.length 就是 0
        for (let i = 0; i < arr.length; i++) {
            if (arr[i] >= 10) {
                // 新数组索引号应该从0开始 依次递增
                newArr[newArr.length] = arr[i];
            }
        }
        console.log(newArr); //(3)[77,52,25]
    </script>
</head>

<body>

</body>

</html>

5、案例

(1)删除指定数组元素

要求:将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组。
        // 1、需要一个新数组用于存放筛选之后的数据。
        // 2、遍历原来的数组, 把不是 0 的数据添加到新数组里面(此时要注意采用数组名 + 索引的格式接收数据)。
        // 3、新数组里面的个数, 用 length 不断累加。
        let arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
        let newArr = [];
        for (let i = 0; i < arr.length; i++) {
            if (arr[i] != 0) {
                newArr[newArr.length] = arr[i];
            }
        }
        console.log(newArr); // (7) [2,6,1,77,52,25,7]
    </script>
</head>

<body>

</body>

</html>

(2)翻转数组

要求: 将数组 ['red', 'green', 'blue', 'pink', 'purple'] 的内容反过来存放。
输出: ['purple', 'pink', 'blue', 'green', 'red']

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 将数组 ['red', 'green', 'blue', 'pink', 'purple'] 的内容反过来存放
        // 1、声明一个新数组 newArr
        // 2、把旧数组索引号第4个取过来(arr.length - 1),给新数组索引号第0个元素 (newArr.length)
        // 3、我们采取 递减的方式  i--
        var arr = ['red', 'green', 'blue', 'pink', 'purple'];
        var newArr = [];
        for (var i = arr.length - 1; i >= 0; i--) {
            newArr[newArr.length] = arr[i]
        }
        console.log(newArr); // (5) ['purple', 'pink', 'blue', 'green', 'red']
    </script>
</head>

<body>

</body>

</html>

(3)冒泡排序

冒泡排序是一种算法,把一系列的数据按照一定的顺序进行排列显示(从小到大或从大到小)

例如,我们可以将数组 [5, 4, 3, 2, 1]中的元素按照从小到大的顺序排序,输出: 1,2,3,4,5

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 冒泡排序
        // let arr = [5, 4, 3, 2, 1];
        let arr = [4, 1, 2, 3, 5];
        for (let i = 0; i <= arr.length - 1; i++) { // 外层循环管趟数 
            for (let j = 0; j <= arr.length - i - 1; j++) { // 里面的循环管 每一趟的交换次数
                // 内部交换2个变量的值 前一个和后面一个数组元素相比较
                if (arr[j] < arr[j + 1]) {
                    let temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                }

            }
        }
        console.log(arr); // (5) [5, 4, 3, 2, 1]
    </script>
</head>

<body>

</body>

</html>

二、JavaScript 函数

函数:就是封装了一段可被重复调用执行的代码块。通过此代码块可以实现大量代码的重复使用。

1、函数的使用

函数在使用时分为两步:声明函数调用函数

(1)声明函数

  • function 是声明函数的关键字,必须小写
  • 由于函数一般是为了实现某个功能才定义的, 所以通常我们将函数名命名为动词,比如 getSum
// 声明函数
function 函数名() {
    //函数体代码
}

(2)调用函数

  • 调用的时候千万不要忘记添加小括号
  • 口诀:函数不调用,自己不执行。
// 调用函数
函数名();  // 通过调用函数名来执行函数体代码

(3)函数的封装

函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口

案例:利用函数计算1-100之间的累加和

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 利用函数计算1-100之间的累加和 
        // 1. 声明函数
        function getSum() {
            let sum = 0;
            for (let i = 1; i <= 100; i++) {
                sum += i;
            }
            console.log(sum);

        }
        // 2. 调用函数
        getSum(); //5050
        getSum(); //5050
    </script>
</head>

<body>

</body>

</html>

2、函数的参数

(1)形参和实参

声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参,而在调用该函数时,同样也需要传递相应的参数,这些参数被称为实参

参数说明
形参形式上的参数 函数定义的时候传递的参数 当前并不知道是什么
实参实际上的参数 函数调用的时候传递的参数 实参是传递给形参的

参数的作用 : 在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去。

// 带参数的函数声明
function 函数名(形参1, 形参2 , 形参3...) { // 可以定义任意多的参数,用逗号分隔
  // 函数体
}
// 带参数的函数调用
函数名(实参1, 实参2, 实参3...); 

案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 1. 利用函数求任意两个数的和
        function getSum(num1, num2) {
            console.log(num1 + num2);

        }
        getSum(1, 3); // 4
        getSum(3, 8); // 11
        // 2. 利用函数求任意两个数之间的和
        function getSums(start, end) {
            let sum = 0;
            for (let i = start; i <= end; i++) {
                sum += i;
            }
            console.log(sum);

        }
        getSums(1, 100); // 5050
        getSums(1, 10); //55
        // 3. 注意点
        // (1) 多个参数之间用逗号隔开
        // (2) 形参可以看做是不用声明的变量
    </script>
</head>

<body>

</body>

</html>

(2)函数形参和实参个数不匹配问题

参数个数说明
实参个数等于形参个数输出正确结果
实参个数多于形参个数只取到形参的个数
实参个数小于形参个数多的形参定义为undefined
function sum(num1, num2) {
    console.log(num1 + num2);
}
sum(100, 200);             // 形参和实参个数相等,输出正确结果
sum(100, 400, 500, 700);   // 实参个数多于形参,只取到形参的个数
sum(200);                  // 实参个数少于形参,多的形参定义为undefined,结果为NaN

3、函数的返回值

(1)return语句

  • 使用 return 语句时,函数会停止执行,并返回指定的值
  • 如果函数没有 return ,返回的值是 undefined
// 声明函数
function 函数名(){
    ...
    return  需要返回的值;
}
// 调用函数
函数名();    // 此时调用函数就可以得到函数体内return 后面的值

案例

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 利用函数 求两个数的最大值
        function getMax(num1, num2) {
            // if (num1 > num2) {
            //     return num1;
            // } else {
            //     return num2;
            // }
            return num1 > num2 ? num1 : num2;
        }
        console.log(getMax(1, 3)); // 3
        console.log(getMax(11, 3)); // 11
    </script>
</head>

<body>

</body>

</html>

(2)return终止函数

return 后的代码不执行

function add(num1,num2) {
    //函数体
    return num1 + num2; // 注意:return 后的代码不执行
    alert('我不会被执行,因为前面有 return');
}
let resNum = add(21, 6); // 调用函数,传入两个实参,并通过 resNum 接收函数返回值
alert(resNum);          // 27

(3)return的返回值

return 只能返回一个值。如果用逗号隔开多个值,以最后一个为准。

function fn(num1, num2) {
    return num1, num2; // 返回的结果是最后一个值
}
console.log(fn(1, 2)); //2

如果想返回多个值,可利用数组实现,案例如下:

//求任意两个数的 加减乘数结果
function getResult(num1, num2) {
    return [num1 + num2, num1 - num2, num1 * num2, num1 / num2];
}
let re = getResult(1, 2); // 返回的是一个数组
console.log(re); // (4) [3,-1,2,0.5]

(4)函数没有return返回undefined

  • 函数都是有返回值的
  • 如果有return 则返回 return 后面的值
  • 如果没有return 则返回 undefined

(5)break ,continue ,return 的区别

  • break :结束当前的循环体(如 for、while)
  • continue :跳出本次循环,继续执行下次循环(如 for、while)
  • return :不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码

4、arguments的使用

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

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

  • 具有 length 属性
  • 按索引方式储存数据
  • 不具有数组的 push , pop 等方法

案例:利用函数求任意个数的最大值

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 利用函数求任意个数的最大值
        function getMax() { // arguments = [1,2,3]
            let max = arguments[0];
            for (let i = 1; i < arguments.length; i++) {
                if (arguments[i] > max) {
                    max = arguments[i];
                }
            }
            return max;
        }
        console.log(getMax(1, 2, 3)); // 3
        console.log(getMax(1, 2, 3, 4, 5)); // 5
        console.log(getMax(11, 2, 34, 444, 5, 100)); // 444
    </script>
</head>

<body>

</body>

</html>

5、案例

(1)判断闰年

要求:输入一个年份,判断是否是闰年(闰年:能被4整除并且不能被100整数,或者能被400整除)

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 利用函数判断闰年
        function isRunYear(year) {
            // 如果是闰年我们返回 true  否则 返回 false 
            let flag = false;
            if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
                flag = true;
            }
            return flag;
        }
        console.log(isRunYear(2000)); // true
        console.log(isRunYear(1999)); // false
    </script>
</head>

<body>

</body>

</html>

(2)函数相互调用

用户输入年份,输出当前年份2月份的天数;
如果是闰年,则2月份是 29天, 如果是平年,则2月份是 28天。

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 用户输入年份,输出当前年份2月份的天数
        function backDay() {
            let year = prompt('请您输入年份:');
            if (isRunYear(year)) { // 调用函数需要加小括号
                alert('当前年份是闰年2月份有29天');
            } else {
                alert('当前年份是平年2月份有28天');
            }
        }
        backDay();


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

<body>

</body>

</html>

6、函数的两种声明方式

(1)自定义函数方式

利用函数关键字 function 自定义函数方式。

// 声明定义方式
function fn() {...}
// 调用  
fn();  
  • 因为有名字,所以也被称为命名函数
  • 调用函数的代码既可以放到声明函数的前面,也可以放在声明函数的后面

(2)函数表达式方式(匿名函数)

// 这是函数表达式写法,匿名函数后面跟分号结束
let fn = function(){...}// 调用的方式,函数调用必须写到函数体下面
fn();
  • 因为函数没有名字,所以也被称为匿名函数
  • 这个fn 里面存储的是一个函数
  • fn变量名, 不是函数名
  • 函数表达式方式原理跟声明变量方式是一致的
  • 函数调用的代码必须写到函数体后面

三、综合案例:简易计算器

在这里插入图片描述

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        let money = 100;
        let action;
        let select = function () {
            do {
                action = prompt("欢迎使用简易计算器:\n1、加法运算\n2、减法运算\n3、乘法运算\n4、除法运算\n5.退出\n请输入您的选项:");
                let number;
                let result = 0;
                switch (action) {
                    case '1':
                        number = getValue();
                        result = parseFloat(number[0]) + parseFloat(number[1]);
                        alert("结果为" + result);
                        break;
                    case '2':
                        number = getValue();
                        result = number[0] - number[1];
                        alert("结果为" + result);
                        break;
                    case '3':
                    number = getValue();
                        result = number[0] * number[1];
                        alert("结果为" + result);
                        break;
                    case '4':
                    number = getValue();
                        result = number[0] / number[1];
                        alert("结果为" + result);
                        break;
                    case '5':
                        alert("您正在退出!")
                        break;
                    default:
                        alert("请输入正确选项!");
                }
            } while (action !== '5');
        }

        function getValue() {
            let value = [];
            for (i = 0; i < 2; i++) {
                value[i] = prompt("请输入一个数值")
            }
            return value;
        }

        select();
    </script>
</head>

<body>

</body>

</html>

四、JavaScript 作用域

通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。

JavaScript(es6前)中的作用域有两种:

  • 全局作用域
  • 局部作用域(函数作用域):

1、全局作用域、全局变量

  • 全局作用域作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
  • 在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)

注意: 如果在函数内部,没有声明直接赋值的变量也属于全局变量(不建议使用)

let num = 10; // num就是一个全局变量
console.log(num); // 10

function fn() {
	console.log(num); // 10
	num2 = 20; // 如果在函数内部 没有声明直接赋值的变量也属于全局变量
}

fn();

console.log(num); // 10
console.log(num2); // 20

2、局部作用域、局部变量

  • 作用于函数内的代码环境,就是局部作用域。 因为跟函数有关系,所以也称为函数作用域
  • 在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)

注意: 函数的形参也可以看做是局部变量

function fun(aru) {
    let num1 = 10; // num1就是局部变量 只能在函数内部使用
    console.log(num1); //10
    console.log(aru); //20
}
fun(10);
// console.log(num1); // 报错
console.log(aru); // 报错  函数的形参也可以看做是局部变量

3、JS 没有块级作用域(在ES6之前)

块作用域由 { } 包括

Js中没有块级作用域(在ES6之前)。

if (true) {
    var num4 = 123;
    console.log(num4); //123
}
console.log(num4);   //123

使用let定义变量是具有块级作用域

if (true) {
    let num4 = 123;
    console.log(num4); //123
}
console.log(num4);   //报错

for(i=0;i<2;i++){
    let temp=80;
    console.log(temp); //80
}
console.log(temp); //报错

4、全局变量和局部变量的区别

  • 全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
  • 局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间

5、作用域链

  • 只要是代码,就至少有一个作用域
  • 写在函数内部的局部作用域
  • 如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
  • 根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
// 作用域链  : 内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值 这种结构我们称为作用域链   
// 就近原则
let text = 10;

function fn() { // 外部函数
    let text = 20;

    function fun() { // 内部函数
        console.log(text); //20

    }
    fun();
}
fn();

案例:结果是几?

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 案例1 : 结果是几?
        function f1() {
            var num = 123;

            function f2() {
                var num = 0;
                console.log(num); // num = 0 站在目标出发,一层一层的往外查找
            }
            f2();
        }
        var num = 456;
        f1();
        
        // 案例2 :结果是几?
        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();
    </script>
</head>

<body>

</body>

</html>

五、JavaScript 预解析

  • JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。
  • JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行
  • 预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 varfunction 声明的变量在内存中进行提前声明或者定义。
  • 代码执行: 从上到下执行JS语句。
  • 预解析也叫做变量、函数提升。
  • let声明的变量不具备变量提升

1、变量预解析(变量提升)

  • 变量提升: 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升
  • let声明的变量不具备变量提升
 //变量提升使num声明放在了最前面
 console.log(num); // undefined  坑 
 var num = 10;

相当于以下代码:

var num;
console.log(num);
num = 10;

2、函数预解析(函数提升)

  • 函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数
 //函数提升使fn声明放在了最前面
 fn(); // 11   放在函数前后皆可
 function fn() {
     console.log(11);
 }

3、解决函数表达式(匿名函数)声明调用问题

  • 匿名函数会进行变量提升变量的赋值(函数)不会提升,因此报错
  • 解决方法:函数调用的代码必须写到函数体后面
//变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升
 fun(); // 报错  
 var fun = function () {
     console.log("想不到吧");
 }

相当于以下代码:

 var fun;
 fun();
 fun = function() {
     console.log("想不到吧");
 }

4 、案例

注意:

  • var a2 = b2 = c2 = 9; 其中, b2c2 直接赋值, 没有var 声明
  • 相当于var a2 = 9; b2 = 9; c2 = 9;
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
    <script>
        // 案例 1
        alert(a); //函数a
        var a = 1;
        alert(a); // 1
        function a() {
            return false;
        }

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

        // 案例3
        var num1 = 10;
        function fn() {
            console.log(num1); //undefined
            var num1 = 20;
            console.log(num1); //20
        }
        fn();

        // 案例4
        var a1 = 18;
        f1();
        function f1() {
            var b1 = 9;
            console.log(a1); //undefined
            console.log(b1); //9
            var a1 = '123';
        }

        console.log('-----------------------------------');
        // 案例5
        f2();
        console.log(c2); //9
        console.log(b2); //9
        console.log(a2); //报错
        function f2() {
            var a2 = b2 = c2 = 9; //b2 和 c2 直接赋值 没有var 声明 当 全局变量看
            console.log(a2); //9
            console.log(b2); //9
            console.log(c2); //9
        }
        // 相当于以下代码
        // function f2() {
        //      var a2;
        //      a2 = b2 = c2 = 9;
        //      //相当于 var  a2  = 9; b2 = 9; c2 = 9; 
        //      //b2 和 c2 直接赋值 没有var 声明 当 全局变量看
        //      //集体声明  var a2 = 9, b2 = 9, c2 = 9;
        //      console.log(a2); //9
        //      console.log(b2); //9
        //      console.log(c2); //9
        // }
        // f2();
        // console.log(c2); //9
        // console.log(b2); //9
        // console.log(a2); //报错
    </script>
</head>

<body>

</body>

</html>
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值