zoukankan      html  css  js  c++  java
  • JS变量、作用域、 内存(含 预解析面试题)

    一、变量

    1. 变量 命名:

    • 变量名以$、字母、下划线开头
    • 驼峰命名法
    • 变量名要有意义

    2. 变量 声明

    • 声明多个变量:var message, name, age;

    • 重复声明无效,只看第一次声明【特殊:函数内形参 与 函数内的函数名(函数声明方式创建的函数) 重名,以函数名声明为准】

    <script>
        console.log(typeof a);
    
        function a() {}
    
        var a = 10;
    </script>
    // 输出:function
    
    <script>
        var a = 10;
        
        function a() {}
        
        console.log(typeof a);
    </script>
    // 输出:number
    
    <script>
        (function(a) {
            console.log(a);
            var a = function() {}
            console.log(a);
        })(100);
    </script>
    // 输出: 100  函数体
    
    // 特殊情况
    <script>
        (function(a) {
            console.log(a);
            function a() {}
            console.log(a);
        })(100);
    </script>
    // 输出: 函数体  函数体
    

    3. 变量 赋值(初始化) 延作用域链寻找变量,然后赋值

    • 多次赋值有效,产生覆盖,只看最后一次赋值(注意区分:变量的声明)

    • 变量赋值过程:沿着作用域链,找变量进行赋值;有则赋值,没有则一直找到全局环境中中, 若全局环境中没有,就创建全局变量,再赋值

    • 所以,没用var 声明的变量,是全局变量

    4. 按作用域区分:

    局部变量:用var声明;注意区分:声明、初始化(赋值)
    全局变量:不用var 声明。 不推荐

    二、变量的 数据类型:简单数据类型 、 复杂数据类型

    • JS有6种数据类型:5种简单数据类型、1种复杂数据类型
    • 乍一看6种数据类型,不足以表示所有数据;但由于ECMAScript数据具有动态性,就没必要再定义其他数据类型了

    1. 检测变量的数据类型 ---> typeof 操作符

    • typeof() 是操作符,不是函数
    • 用法:
      • typeof(变量)
      • typeof 变量
    • 返回:
      • typeof(变量) = undefined:声明变量,但未初始化(赋值);如果未声明变量,则报错
      • typeof(变量) = boolean:变量是布尔
      • typeof(变量) = string:变量是字符串
      • typeof(变量) = number:变量是数值
      • typeof(变量) = object:变量是对象 或 null(特殊:null 的数据类型是object)
      • typeof(变量) = function:变量是函数

    2. undefined 类型

    • 该数据类型只有一个值,值为本身undefined
    • 变量为undefined类型:变量被声明(var),但未初始化 / 赋值

    3. null 类型

    • 该数据类型只有一个值,值为本身null
    • null 表示一个空对象指针,只要想保存对象的变量还没有真正保存对象,就可以用这个变量保存null
    • nullundefined 是完全不同的两个值,但 null == undefined 返回 true

    4. boolean 类型

    • 所有变量都能转为 布尔值,布尔类型只有两个值true 、 false
    • 转布尔值函数:Boolean()
    空字符串、0、NaN、null、undefined 转布尔值为 `false`
    特殊:空对象 转布尔值 为true
    

    5. number 类型

    • 这种类型使用IEEE745格式来表示:整数浮点数值
    二进制(0、1)
    八进制(第一位是0,范围0 ~ 7)
    十进制(0 ~ 9)
    十六进制(开头是0x,范围0 ~ 9,A ~ F 字母部分大小写)
    
    浮点数值:浮点数值中必须有一个小数点,且小数点后最少有一位小数;
    浮点值计算不准确
    
    内存空间:整数值内存空间的两倍 === 浮点数值内存空间;所以 1.0 会被转为整数值 1 再被存储
    
    • js的数值范围
      • ECMAScript 不能保存世界上所有的数值
      • 判断数值是否处于 js的数值范围isFinite()
    最小值:Number.MIN_VALUE 
    最大值:Number.MAX_VALUE
    正无穷:Infinity
    负无穷:-Infinity 
    
    • NaN:(这不是一个数值)但它是一个特殊的数值
      • NaN和任何数值都不相等,包括本身
      • isNaN() 验证是不是一个数值,会发生隐式转化
    isNaN(NaN);     // true
    isNaN(10);      // false
    isNaN("10");    // false (默认转为数值)
    isNaN(true);    // false (true转为1)
    isNaN("blue");  // true
    isNaN("aa11");  // true
    
    • 数值转化 (null会被转为数值,undefined 会被转为NaN)
      • Number() 可用以任何数据类型;特殊情况(转换非纯数值的字符串、对象、undefined值为NaN;转换布尔值、null、纯数值字符串,可转为数值)
      • 向下整数转化parseInt(string / number, radix)(第二个参数转为几进制):字符串开头如果不是数字,则返回NaN;字符串开头是数字,一直解析到不是数字的停止且不会保留小数
      • 浮点转化parseFloat(string / number):字符串开头如果不是数字,则返回NaN;字符串开头是狮子,一直解析到不是数字的停止且会保留小数
      • parseInt() / parseFloat() 的参数也可以是数值,但一般不这样使用
      • toFixed(几位小数) 保留几位小数; ---> 返回字符串
    parseInt('112ac.44');       // 112
    parseInt('ac112.44');       // NaN
    parseFloat("34 45 66");     // 34
    parseFloat('22.34a5');      // 22.34
    

    6. string类型

    • 字符串特点:不可变;数组可变
    • String(变量) 可以将任意类型的数据 转为字符串
    • 变量.toString() 不能转化null 和 undefined,会报错

    7. object类型

    • 复杂数据类型:是一种数据和功能的集合

    三、变量的类型值

    基本值类型

    • 简单的数据类型属于基本类型值:null、undefined、boolean、number、string

    • 深拷贝(保存在栈内存中):相当于 重新创建一个变量,两个值互不影响

    引用类型值

    • 复杂数据类型属于引用类型值:object

    • 通过 . 的方式引用类型值得变量添加属性、方法 ---> 由此得出 JS是一门动态型的语言,数据松散型。

    • 浅拷贝(保存在堆内存中):引用类型的变量实际上包含的并不是对象本身,而是一个指向该对象的指针;从一个变量向另一个变量复制引用类型的值,实际上复制的是指针,两个变量最终指向同一个对象

    • delete 对象.方法 / 属性 删除 引用类型的 属性、方法

    判断 变量的类型值

    • 判断一个值是哪种基本类型用: typeof

    • 判断一个值是哪种引用类型用:对象 instanceof 引用类型的构造函数,返回布尔值

    四、变量的 作用域

    1. 全局 作用域 / 全局变量

    • 全局执行环境被认为是window对象,所有全局变量都是 window的属性 和 方法

    • 全局变量:直接在<script> </script> 中定义的变量

    2. 局部 作用域 / 局部变量 ---> 只针对函数而言,也称词法作用域

    • 局部变量:在局部作用域重定义的变量;局部作用域之外是不能访问到的

    • 局部作用域中:不用 var 声明的变量,会被自动添加到全局环境中

    • 函数的局部环境不仅有权访问本级作用域,还可以访问父级作用域;父级作用域不能访问子级作用域【跨作用域访问变量,只能访问外层作用域,不能访问内层作用域】

    3. ES5 中 表示:变量没有块级作用域,局部作用域(词法作用于) 只针对函数

    • 所以并不是 { } 就是一个块级作用域;局部作用域只针对函数,不针对 if 、 for 语句

    • ES6 对 块级作用域 进行了改善

    4. 变量 作用域链

    • 概念: 以函数为例,每一个函数都有一个作用域,这个作用域若包裹在其他函数中,包裹他的函数也有作用域,这样直到全局作用域,就形成了一条作用域链式结构,把这个链式结构称作:作用域链。

    • 每次进入一个新的执行环境,都会创建一条用于搜索变量、函数的作用域链。

    5. 变量 搜索原则

    • 只找声明, 首先在当前作用域找,没有话再去外层作用域查找;知道找到window全局作用域

    五、变量 预解析

    1. 预解析 概念:提升 变量声明 到当前作用域最顶部

    • 把变量(基本类型值变量/ 复杂类型值变量) 的声明 提前到当前作用域的最顶层;但初始化(赋值)没有被提前

    2. 基本类型变量预解析 / 函数预解析

    • 变量的声明提升

      • var aaa; 提升,赋值不提升

      • 输出 未赋值的变量,结果为undefined

    • 函数的声明提升【重要】

      • 调用 未赋值的函数,报错
    function  fn ()  {}    整体提升函数体
    
    var  fn = function() {}   只提升var  fn ;
    

    3. 预解析 题目分析思路

    • 当前作用域中,先提升变量 / 提升函数名;代码 从上到下,从左到右执行

    • 发现函数调用,则回到函数创建区域执行函数

    • 重复声明无效,只看第一次声明【特殊:函数内形参 与 函数内的函数名(函数声明方式创建的函数) 重名,以函数名声明为准】

      • 函数声明方式创建:function fn() { } 预解析是把:整个函数体提前

      • 函数表达式方式创建:var fn = function() { } 预解析是把:var fn; 提前

    预解析面试题

    • 第1题:输出什么
    <script>
        console.log(typeof a);
    
        function a() {}
    
        var a = 10;
    </script>
    
    • 第2题:输出什么
    <script>
        var a = 10;
        
        function a() {}
        
        console.log(typeof a);
    </script>
    
    • 第3题:输出什么
    <script>
        (function(num) {
            console.log(num);
            num = 123;
            console.log(num);
        })(100);
    </script>
    
    • 第4题:输出什么
    <script>
        (function(a) {
            console.log(a);
            var a = function() {}
            console.log(a);
        })(100);
    </script>
    
    • 第5题:输出什么
    <script>
        (function(a) {
            console.log(a);
            function a() {}
            console.log(a);
        })(100);
    </script>
    
    • 第6题:输出什么【重要】
    <script>
        var x = 1;
        function a(x) {
            x = 2;
            return x;
        }
    
        a(x);
        console.log(x);
    </script>
    
    • 第7题:输出什么 【重要】
    <script>
        var num = 123;
        function f1() {
            console.log(num);
        }
    
        f2();
        function f2() {
            num = 456;
            f1();
        }
    
        console.log(num);
    </script>
    
    • 第8题:输出什么 【重要】
    <script>
        if ('a' in window) {
            var a = 10;
            console.log('进入');
        }
    
        console.log(a);
    </script>
    

    预解析面试题 答案

    • 第1题: function
    • 第2题: number
    • 第3题: 100 123
    • 第4题: 100 函数体
    • 第5题: 函数体 函数体
    • 第6题: 1 因为函数内 x 是函数参数,可理解为函数内的局部变量,函数外不能访问到
    • 第7题: 456 456
    • 第8题: 10 任何一个未声明的属性 都在 window的原型链上

    六、变量的生命周期

    局部作用域

    • 代码执行完,局部执行环境就会被销毁;所有的变量、函数 都会被立刻销毁

    全局作用域(window)

    • 直到应用程序退出(关闭浏览器等),全局执行环境才会被销毁

    七、内存泄露

    1. 内存泄露 概念

    • 内存泄露:指程序中间动态分配了内存,但在程序结束时没有释放这部分内存;

    • 重启计算机,或关闭程序 可以解决内存泄露

    • 内存泄露,和计算机硬件没关系,和软件代码书写有关

    2. 内存泄露 导致的问题

    3. JS中解决方案:js垃圾自动回收机制

    • JS垃圾自动回收机制原理:垃圾回收器,会间隔一段时间,将不再使用的 局部变量 销毁,释放其占用的内存

    • 但 C、C#等语言,需要手动跟踪内存的使用情况

    4. JS中解决方案:js中 全局变量 / 引用类型变量 需要手动 释放内存

    • 变量不在被引用,即释放掉内存

    • 变量 = null;

    八、内存溢出 ---> 解决方案:数据缓存

    1. 内存溢出 概念

    • 内存溢出即用户在对其数据缓冲区操作时,超过了其缓冲区的边界

    2. 内存溢出导致问题

    3. JS中解决方案:对象 / 数组 模拟缓存数据

    • 将需要缓存的数据,存储到 对象 / 数组 中
    缓存作用
    • 暂存数据,避免做重复计算 / 请求;提高程序运行效率
    缓存使用步骤
    • (1) 使用数据,先到缓存中查看,有则取出使用
    • (2) 缓存中没数据,则计算 / 请求,再将数据缓存起来
    缓存应用:斐波那契递归函数
    • 菲波那切数列 优化【缓存】
    <script>
        var cache = {};
    
        function fn4(m) {
            if (cache[m]) {
                return cache[m];
            }
    
            if (m === 1 || m === 2) {
                cache[m] = 1;
                return 1;
            } else {
                return cache[m] = fn4(m-1) + fn4(m-2);
            }
        }
    
        console.log(fn4(200));
    </script>
    

    九、内存泄露 与 内存溢出的关系

    • 内存泄露是导致内存溢出的原因之一;内存泄露积累起来将导致内存溢出

    • 内存泄露可以通过完善代码来避免

    • 内存溢出可以通过调整配置来减少发生频率,但无法彻底避免

  • 相关阅读:
    windbg 常用命令
    逐梦
    字体反爬个人心得
    Python字典及基本操作
    openCV学习笔记(3)边缘检测和模板匹配
    使用selenium被识别的解决方法
    使用python发送QQ邮件,以及添加附件
    selenium.common.exceptions.JavascriptException: Message: javascript error: Cannot set property 'playbackRate' of null的解决
    (2)进程管理
    error: (-215:Assertion failed) (depth == CV_8U || depth == CV_32F) && _img.dims() <= 2 in function 'cv::matchTemplate'等opencv踩过的坑
  • 原文地址:https://www.cnblogs.com/zxvictory/p/8001571.html
Copyright © 2011-2022 走看看