JavaScript零基础通关(9)作用域,块级作用域,局部变量,作用域链,变量预解析和函数预解析

JavaScript 作用域

  1. 作用域
    1.1 作用域概述
    通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
    一段程序代码所用到的名字并不总是有效的可用的,
    JavaScript(es6前)中的作用域有两种:
    全局作用域
    局部作用域(函数作用域)
    全局,函数局部作用域
    1.2 全局作用域
    作用于所有代码执行的环境(整个 script 标签内部)或者一个独立的 js 文件。
    作用于所有代码执行的环境
    1.4 JS 没有块级作用域
    块作用域由 { } 包括。
    在其他编程语言中(如 java、c#等),在 if 语句、循环语句中创建的变量,仅仅只能在本 if 语句、本循环语句中使用,如下面的Java代码:
    块级作用域由{}包括
if(true){
    
    
  int num = 123;
  system.out.print(num);  // 123
}
system.out.print(num);    // 报错

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

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

2. 变量的作用域

2.1 变量作用域的分类
在JavaScript中,根据作用域的不同,变量可以分为两种:
全局变量
局部变量
2.2 全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)。
全局变量在代码的任何位置都可以使用
在全局作用域下 var 声明的变量 是全局变量
特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
全局变量在代码的任何位置都可以使用,
2.2 局部变量
在局部作用域下声明的变量叫做局部变量(在函数内部定义的变量)
局部变量只能在该函数内部使用
在函数内部 var 声明的变量是局部变量
函数的形参实际上就是局部变量
在局部作用域下声明的变量叫做局部变量
在函数内部var声明的变量是局部变量
函数的形参实际上就是局部变量
2.3 全局变量和局部变量的区别
全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
全局变量:在任何一个地方都可以使用,再有在浏览器关闭的时候才会销毁,
局部变量:只在函数内部使用,当其所在的代码块执行的时候,会被初始化,
3. 作用域链
只要是代码,就至少有一个作用域
写在函数内部的局部作用域
如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链
写在函数内部的局部作用域,如果函数当中还有函数,那么在这个作用域当中就可以诞生一个作用域
根据在内部函数可以访问外部函数变量的机制,用链式查找决定哪些数据能被内部函数访问,作用域链
案例 1: 结果是几?

function f1() {
    
    
    var num = 123;
    function f2() {
    
    
        console.log( num );
    }
    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的值 ?
            console.log(b); //b的值 ?
        }
    }
}
fn1();

只有函数才会有arguments对象,而且是每个函数都内置好了这个arguments

<!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>
        // arguments 的使用  只有函数才有 arguments对象  而且是每个函数都内置好了这个arguments
        function fn() {
    
    
            // console.log(arguments); // 里面存储了所有传递过来的实参  arguments = [1,2,3]
            // console.log(arguments.length);
            // console.log(arguments[2]);
            // 我们可以按照数组的方式遍历arguments
            for (var i = 0; i < arguments.length; i++) {
    
    
                console.log(arguments[i]);

            }
        }
        fn(1, 2, 3);
        fn(1, 2, 3, 4, 5);
        // 伪数组 并不是真正意义上的数组
        // 1. 具有数组的 length 属性
        // 2. 按照索引的方式进行存储的
        // 3. 它没有真正数组的一些方法 pop()  push() 等等
    </script>
</head>

<body>

</body>

</html>

伪数组不是真正意义上的数组,length属性,按照索引方式进行存储,没有真正数组的一些方法pop(),push();

<!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]
            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>
</head>

<body>

</body>

</html>

if(arguments[i]>max){max=arguments[i];
for(var i=1;i<arguments.length;i++){if(arguments[i]>max}

03-利用函数翻转数组

<!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>
        // 利用函数翻转任意数组 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);
    </script>
</head>

<body>

</body>

</html>

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,2,3,4,6,9]);
console.log(arr1);
var arr2=reverse([‘red’,‘pink’,‘blue’]);

04-利用函数冒泡

<!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>
        // 利用函数冒泡排序 sort 排序
        function sort(arr) {
    
    
            for (var i = 0; i < arr.length - 1; i++) {
    
    
                for (var j = 0; j < arr.length - i - 1; j++) {
    
    
                    if (arr[j] > arr[j + 1]) {
    
    
                        var temp = arr[j];
                        arr[j] = arr[j + 1];
                        arr[j + 1] = temp;
                    }
                }
            }
            return arr;
        }
        var arr1 = sort([1, 4, 2, 9]);
        console.log(arr1);
        var arr2 = sort([11, 7, 22, 999]);
        console.log(arr2);
    </script>
</head>

<body>

</body>

</html>

利用函数判断闰年

<!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 
            var flag = false;
            if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
    
    
                flag = true;
            }
            return flag;
        }
        console.log(isRunYear(2000));
        console.log(isRunYear(1999));
    </script>
</head>

<body>

</body>

</html>

function isRunYear(year){var flag=false;if(year%40&&year%100!=0||year%4000)

06函数是可调用的

<!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 fn1() {
    
    
        //     console.log(11);
        //     fn2(); // 在fn1 函数里面调用了 fn2 函数
        // }
        // fn1();

        // function fn2() {
    
    
        //     console.log(22);

        // }

        function fn1() {
    
    
            console.log(111);
            fn2();
            console.log('fn1');
        }

        function fn2() {
    
    
            console.log(222);
            console.log('fn2');
        }
        fn1();
    </script>
</head>

<body>

</body>

</html>

function fn1(){console.log(11);fn2();}

07-输出年份

<!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() {
    
    
            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;
        }
    </script>
</head>

<body>

</body>

</html>

function isRunYear(year){var fla=true;if(year%40&&year%100!=0||year%400=0){flag=true;}return falg;}

08-函数的两种声明方式

<!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中声明方式
        // 1. 利用函数关键字自定义函数(命名函数)
        function fn() {
    
    

        }
        fn();
        // 2. 函数表达式(匿名函数) 
        // var 变量名 = function() {
    
    };
        var fun = function(aru) {
    
    
            console.log('我是函数表达式');
            console.log(aru);

        }
        fun('pink老师');
        // (1) fun是变量名 不是函数名  
        // (2) 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而 函数表达式里面存的是函数
        // (3) 函数表达式也可以进行传递参数
    </script>
</head>

<body>

</body>

</html>

var fun=function(aru){console.log(‘我是函数表达式’);}
fun(’pink来说’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>
        // 1.JavaScript作用域 : 就是代码名字(变量)在某个范围内起作用和效果 目的是为了提高程序的可靠性更重要的是减少命名冲突
        // 2. js的作用域(es6)之前 : 全局作用域   局部作用域 
        // 3. 全局作用域: 整个script标签 或者是一个单独的js文件
        var num = 10;
        var num = 30;
        console.log(num);

        // 4. 局部作用域(函数作用域) 在函数内部就是局部作用域 这个代码的名字只在函数内部起效果和作用
        function fn() {
    
    
            // 局部作用域
            var num = 20;
            console.log(num);

        }
        fn();
    </script>
</head>

<body>

</body>

</html>

全局作用域:整个script标签,或者是一个单独的js文件,整个script标签,或者是一个单独的js文件
在函数内部没有声明直接赋值的变量也称为全局变量。

JavaScript 预解析

1. 预解析

1 问:

console.log(num);  // 结果是多少?

2 问:

console.log(num);  // 结果是多少?
var num = 10;

3 问:

fn();
function fn() {
    
    
    console.log('打印');
}

4 问:

fn();
var  fn = function() {
    
    
    console.log('想不到吧');
}

var fn=function(){console.log(‘想不到吧’);}
var fn=function(){conssole.log(‘想不到把’);}
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
预解析:在当前作用域下, JS 代码执行之前,浏览器会默认把带有 var 和 function 声明的变量在内存中进行提前声明或者定义。
代码执行: 从上到下执行JS语句。
预解析只会发生在通过 var 定义的变量和 function 上。学习预解析能够让我们知道为什么在变量声明之前访问变量的值是 undefined,为什么在函数声明之前就可以调用函数。

昱解析
浏览器会默认把带有var和function声明的变量在内存当中进行提前声明或者定义
代码执行:从上到下执行JS语句

2. 变量预解析和函数预解析

2.1 变量预解析(变量提升)
变量预解析:变量提升,
预解析也叫做变量、函数提升。
变量提升: 变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升。
变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升
变量提升:变量的声明会被提升到当前作用域的最上面,变量的赋值不会提升

console.log(num);  // 结果是多少?
var num = 10;      // ?

昱解析:变量,函数提升
2.2 函数预解析(函数提升)
函数提升: 函数的声明会被提升到当前作用域的最上面,但是不会调用函数。
函数的声明会被提升到当前作用域的最上面,但是不会调用函数,函数的声明会被提升到当前作用域的最上面,但是不会调用函数
函数的声明会被提升到当前作用域的最上面,但是不会调用函数,函数声明会被提升到当前作用域的最上面,但是不会调用函数

fn();
function fn() {
    
    
    console.log('打印');
}

2.3 解决函数表达式声明调用问题
解决函数表达式声明调用的问题

fn();
var  fn = function() {
    
    
    console.log('想不到吧');
}

var fn=function(){console.log(‘想不到吧’);}
var fn=function(){console.log(‘想不到吧’);}
练习: 结果是几?

// 练习
alert(a);
var a = 1;
alert(a)
function a(){
    
    
    return false;
}

3. 预解析案例

案例 1: 结果是几?

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

undefined
案例 2: 结果是几?

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

undefined,20
案例 3: 结果是几?

// 案例3
var a = 18;
f1();
function f1() {
    
    
  var b = 9;
  console.log(a);
  console.log(b);
  var a = '123';
}

undefined,9
案例 4: 结果是几?

// 案例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);
}

99999

猜你喜欢

转载自blog.csdn.net/weixin_43428283/article/details/124137728