美文网首页
JavaScript 查缺补漏

JavaScript 查缺补漏

作者: direwolf_ | 来源:发表于2019-06-12 20:00 被阅读0次

    \color{red}{本文并不是详细的 JavaScript 介绍,只是整理了一些自己以前忽略了的知识点以及一些自己的理解。}

    Round 1 数据类型相关

    数据类型

    JavaScript 的数据类型共有六种(ES6 又新增了第七种 Symbol 类型的值):
    数值(number)、字符串(string)、布尔值(boolean)、undefinednull、对象(object)。
    对象又可以分为三个子类:狭义的对象(object)、数组(array)、函数(function)。
    其中数值、字符串、布尔值、undefinednull,合称为基本数据类型;而对象称为引用数据类型。

    什么是基本数据类型?什么是引用数据类型?

    在理解“什么是什么是基本数据类型,什么是引用数据类型”之前,我们先要知道什么是堆内存和栈内存。

    栈内存

    栈内存主要用于简单存储,一般存储一些大小已知或者有上限的变量。栈内存一般为有序存储,容量小,系统分配效率高。

    堆内存

    堆内存主要用于存储一些大小未知变量。堆内存存储时不仅要在堆内存中分配存储区域,还要把引用地址存到栈内存中,效率相对较低。

    基本数据类型

    基本数据是存在栈内存中的简单数据段,可以直接按值访问。
    举个栗子:

    var a = 1;
    var b = a;
    b = 2;
    console.log(a);  //1
    
    1. 声明一个变量 a = 1; 此时 a 被存的栈内存中;
    2. 声明一个变量 b = a; 此时 b 获得了 a 值的拷贝,这个时候虽然两个变量的值相等,但是实际上两个变量是保存了两个不同的基本数据类型;
    3. 改变变量 b = 2; 此时 b 变量发生改变但是不会影响变量 a
    引用数据类型

    引用数据是存在堆内存中的对象,需要通过指向储存对象的内存地址的指针进行访问。
    \color{#FF8247}{javascript不允许直接访问堆内存空间中的位置和操作堆内存空间。}
    举个栗子:

    var obj1 = new Object();
    var obj2 = obj1;
    obj2.attr= "添加属性";
    console.log(obj1.attr); // 添加属性
    
    1. 声明一个对象 obj1 = new Object(); 此时 obj1 被存的栈内存中,而 obj1 所对应的值是存在堆内存中的对象的一个引用地址(指针);
    2. 声明一个对象 obj2 = obj1; 此时 obj2 获得了 obj1 值的拷贝,此时 obj2 就获得了存在堆内存中的对象的引用地址(指针),这样他们共同指向了同一个堆内存中的对象;
    3. 给对象添加属性 obj2.attr= "添加属性"; 此时 obj2 实际上是为堆内存中的对象添加属性,所以 obj1 同样受到影响;

    数据类型确定方法

    使用 typeof 确定数据类型(typeof xxx

    数值 —— number
    字符串 —— string
    布尔值 —— boolean
    函数 —— function
    undefined —— undefined
    [], {}, [...], {...}, null —— object
    \color{#FF8247}{注:null 返回 object 是因为设计之初只把它当作 object 的一种特殊值。}
    \color{#FF8247}{后来 null 独立作为一种单独的数据类型,为了兼容以前的代码,所以 typeof null 返回 object。}

    使用 instanceof 确定数据类型(object instanceof constructor
    使用 Object.prototype.toString 确定数据类型

    null 和 undefined

    null:空值
    undefined:未定义
    undefined == null —— true
    Number(null) —— 0
    Number(undefined) —— NaN

    数值

    JavaScript 内部,所有数字都是以64位浮点数形式储存(1 === 1.0 —— true)。
    \color{#FF8247}{注:小心涉及小数的比较和运算}
    0.1 + 0.2 —— 0.30000000000000004
    0.1 + 0.2 === 0.3 —— false

    国际标准 IEEE 754,JavaScript 浮点数的 64 个二进制位

    • 符号位(第1位):决定正负(0 —— 正数,1 —— 负数)
    • 指数部分(第2位到第12位):决定大小 —— 64 位浮点数的指数部分的长度是11个二进制位,意味着指数部分的最大值是 2047(2的11次方减1)。也就是说,64 位浮点数的指数部分的值最大为 2047,分出一半表示负数,则 JavaScript 能够表示的数值范围为 210242-1023,超出这个范围的数无法表示(正向溢出:返回 Infinity;负向溢出:返回 0)。
    Number.MAX_VALUE // 1.7976931348623157e+308
    Number.MIN_VALUE // 5e-324
    
    • 小数部分(第13位到第64位):决定精度 —— 精度最多只能到53个二进制位,所以,绝对值小于2的53次方的整数,即 -253253 可以精确表示。
    数值表示
    • 自动将数值转为科学计数法的几种情况:
      1. 小数点前的数字多于21位;
      2. 小数点后的零多于5个
    • 进制表示:
      1. 十进制:没有前缀;
      2. 二进制:前缀 0b0B
      3. 八进制:前缀 0o0O(或者有前导0、且只用到0-7的数值);
      4. 十六进制:前缀 0x0X

    \color{#FF8247}{注:出现不属于该进制的数字,就会报错}

    特殊数值
    1. +0 / -0:除了 (1 / +0) === (1 / -0) // false,正零和负零是等价的;
    2. NaNNaN 不等于任何值,包括它本身;
    3. InfinityInfinityNaN 比较,总是返回 false
    数值相关操作
    • parseInt() : 将字符串转为整数
      \color{#FF8247}{注:自动转为科学计数法的数字,parseInt会将科学计数法的表示方法视为字符串,导致一些奇怪的结果}
    • parseFloat() : 将一个字符串转为浮点数
      \color{#FF8247}{注:parseFloat会将空字符串转为NaN}
    • isNaN() : 用来判断一个值是否为 NaN
      \color{#FF8247}{注:1.isNaN为true的值,有可能不是NaN,而是一个字符串;}
      \color{#FF8247}{2.利用NaN是唯一不等于自身的值的特点,进行判断更为可靠}
    • isFinite() : 判断某个值是否为正常的数值
      \color{#FF8247}{注:除了Infinity、-Infinity、NaN和undefined这几个值会返回false,isFinite对于其他的数值都会返回true}

    字符串

    1. 长字符串分成多行,可在每行尾部使用反斜杠;
    2. 反斜杠(\)表示字符(应该字符的 Unicode 码点)的三种用法:
      • \后面紧跟三个八进制数
      • \x 后面紧跟两个十六进制数
      • \u 后面紧跟四个十六进制数
    3. btoa():任意值转为 Base64 编码
      atob():Base64 编码转为原来的值
      \color{#FF8247}{注:非ASCII 码的字符,会报错或btoa(encodeURIComponent(str)) 、 decodeURIComponent(atob(str))}

    对象

    对象相关操作
    • Object.keys:查看一个对象本身的所有属性
    • delete:删除对象的属性,删除成功后返回 true,存在且不得删除返回 false
      \color{#FF8247}{delete命令只能删除对象本身的属性,无法删除继承的属性}
    • in'属性名' in 对象):检查对象是否包含某个属性,包含就返回 true,否则返回 false
      \color{#FF8247}{无法识别哪些属性是对象自身的,哪些属性是继承的}
    • hasOwnProperty对象.hasOwnProperty('属性名')):判断是否为对象自身的属性
    • for...in:遍历一个对象的全部属性
      \color{#FF8247}{遍历所有可遍历(enumerable)的属性,跳过不可遍历的属性}
    • with:方便操作同一个对象的多个属性
      \color{#FF8247}{如果with区块内部有变量的赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量。}
      \color{#FF8247}{无法单纯通过代码块判断是全局变量还是对象的一个属性,不利于代码的除错和模块化,拖慢运行速度,所以不建议使用}
    var obj = {
      a: 1,
    };
    with (obj) {
      a = 2;
      b = 3;
    }
    
    obj.a // 2;
    obj.b // undefined
    b // 3;
    

    函数

    作用域

    \color{#FF8247}{函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域}
    举个栗子:

    var a = 1;
    var x = function () {
      console.log(a);
    };
    function f() {
      var a = 2;
      x();
    }
    f() // 1
    

    函数 x 在声明的时候是处于最外层作用域,即使在函数 f 内部被调用,也不会取 f 内部的变量 a 的值,所以会返回 1 而不是 2

    参数
    1. 有同名的参数,则取最后出现的那个值;
    2. arguments:函数运行时的所有参数,只有在函数体内部,才可以使用
      \color{#FF8247}{正常模式下,arguments可以在运行时修改;严格模式下,修改arguments,不影响真实参数}
      • arguments 转为真正的数组的两种方法:
        var args = Array.prototype.slice.call(arguments);
    var args = [];
    for (var i = 0; i < arguments.length; i++) {
      args.push(arguments[i]);
    }
    
    1. callee:返回它所对应的原函数(可以通过 arguments.callee 调用函数自身)
      \color{#FF8247}{这个属性在严格模式里面是禁用的,因此不建议使用}
    闭包

    闭包的两个最大用处:

    1. 可以读取函数内部的变量,这些变量始终保持在内存中,即闭包的诞生环境一直存在;
      举个栗子:记住上一次调用时的运算结果
    function fun(n) {
      return function () {
        return n++;
      };
    }
    var f = fun(1);
    f() // 1
    f() // 2
    f() // 3
    
    1. 封装对象的私有属性和私有方法

    \color{#FF8247}{外层函数每次运行,都会生成一个新的闭包,而这个闭包又会保留外层函数的内部变量,所以内存消耗很大}

    eval

    只要不是直接调用,都属于别名调用,别名调用的作用域是全局作用域。

    数组
    1. length 最大值是 4294967295;
    2. 数组本质上是对象,所以可以为数组添加属性(但是不影响 length 属性);
    函数相关操作

    name:返回函数的名字

    var myFunc = function () {
      console.log(11111);
    }
    function test(f) {
      return f.name;
    }
    eval(test(myFunc))(); //11111
    new Function('return ' + test(myFunc))()(); //11111
    

    length:返回函数预期传入的参数个数,即函数定义之中的参数个数
    toString:返回函数的源码字符串(原生的函数返回原生代码提示 function (){[native code]}
    \color{#FF8247}{函数内部的注释也可以返回,可以变相实现多行字符串}

    类型转换

    强制转换
    1. Number() —— 数字
      转换规则

    a. 原始类型值
    Number(123) —— 123
    Number('123') —— 123
    Number('123abc') —— NaN
    Number('') —— 0
    Number(true) —— 1
    Number(false) —— 0
    Number(undefined) —— NaN
    Number(null) —— 0
    b. 对象
    Number({a: 1}) —— NaN
    Number([1, 2, 3]) —— NaN
    Number([1]) —— 1

    1. String() —— 字符串
      转换规则同 Number() 只是调换了 valueOf()toString() 的顺序。
      a. 原始类型值
      String(123) —— "123"
      String('abc') —— "abc"
      String(true) —— "true"
      String(undefined) —— "undefined"
      String(null) —— "null"
      b. 对象
      String({a: 1}) —— "[object Object]"
      String([1, 2, 3]) —— "1,2,3"
    2. Boolean() —— 布尔值
      undefinednullfalse0NaN、" "、' ' 为 false,其他都为 true
      空数组([])和空对象({}),都是 true
    隐式转换:
    1. 不同类型的数据互相运算(+-*/
      • +:有可能转为字符串
        注:
        '1' + {} —— "1[object Object]"
        '1' + function (){} —— "1function (){}"
        '1' + undefined —— "1undefined"
        '1' + null —— "1null"
      • -*/:转成数值
    2. 对非布尔值类型的数据求布尔值
      • !():同 Boolean()
    3. 对非数值类型的值使用一元运算符(+/-
      • 转成数值
        注:
        +{} —— NaN
        +{a: 1} —— NaN
        +[] —— 0
        +[1, 2] —— NaN
    4. 比较判断(===!====!=>>=<<=
      • 转成布尔值

    相关文章

      网友评论

          本文标题:JavaScript 查缺补漏

          本文链接:https://www.haomeiwen.com/subject/rmjjzqtx.html