• 《你不知道的JavaScript》整理(五)——值与原生函数


    一、值

    1)数字

    JavaScript只有一种数值类型:number(数字),包括“整数”和带小数的十进制数。

    复制代码
    //数字的语法
    var a = 5E10; // 50000000000
    a.toExponential();  // "5e+10"
    var b = a * a;  // 2.5e+21 
    var c = 1 / a; // 2e-11
    var d = 0.42;
    var e = .42; //数字前面的0可以省略
    var f = 42.; //小数点后小数部分最后面的0也可以省略
    复制代码

    由于数字值可以使用Number对象进行封装,因此数字值可以调用Number.prototype中的方法。例如,tofixed(..)方法可指定小数部分的显示位数:

    复制代码
    // 无效语法:
    42.toFixed( 3 );    // SyntaxError
    // 下面的语法都有效:
    a = (42).toFixed(3); // "42.000" 
    b = 0.42.toFixed(3); // "0.420" 
    c = 42..toFixed(3); // "42.000"
    d = 42 .toFixed(3); // "42.000"
    复制代码

    2)整数检测

    复制代码
    //整数检测
    if (!Number.isInteger) {
      Number.isInteger = function(num) {
        return typeof num == "number" && num % 1 == 0;
      };
    }
    //安全整数检测
    if (!Number.isSafeInteger) {
      Number.isSafeInteger = function(num) {
        return Number.isInteger(num) &&
          Math.abs(num) <= Number.MAX_SAFE_INTEGER;
      };
    }
    复制代码

    3)null与undefined

    特殊数值undefined与null。它们的名称既是类型也是值。

    null指空值(empty value),曾赋过值,但是目前没有值。null是一个特殊关键字,不是标识符,我们不能将其当作变量来使用和赋值。

    undefined指没有值(missing value),从未赋值。undefined是一个标识符,可以被当作变量来使用和赋值。

    复制代码
    //将undefined当作变量来使用和赋值
    function foo() {
      "use strict";
      var undefined = 2;
      console.log(undefined); // 2
    }
    foo();
    复制代码

    4)不是数字的数字

    NaN意指“不是一个数字”(not a number),将它理解为“无效数值”、“失败数值”或者“坏数值”可能更准确些。

    NaN是一个特殊值,它和自身不相等,是唯一一个非自反(自反,即x === x不成立)的值。而NaN != NaN为true。

    复制代码
    var a = 2 / "foo"; // NaN
    typeof a === "number"; // true
    if (!Number.isNaN) {
      Number.isNaN = function(n) { //非数字类型的值在isNaN中也会返回true
        return (
          typeof n === "number" &&
          window.isNaN(n)
        );
      };
    }
    //利用NaN不等于自身这个特点
    if (!Number.isNaN) {
      Number.isNaN = function(n) {
        return n !== n;
      };
    }
    复制代码

    5)零值

    加法和减法运算不会得到负零(negative zero)。负零在开发调试控制台中通常显示为“-0”,但在一些老版本的浏览器中仍然会显示为“0”。

    复制代码
    //零值
    a = 0 / -3; // -0
    b = 0 * -3; // -0
    c = +"-0"; // -0
    d = Number("-0"); // -0
    e = JSON.parse("-0"); // -0
    //值比较
    -0 == 0; // true
    -0 === 0; // true
    0 > -0; // false
    //-0的判断方式
    function isNegZero(n) {
      n = Number(n);
      return (n === 0) && (1 / n === -Infinity);
    }
    isNegZero(-0); // true
    isNegZero(0 / -3); // true
    isNegZero(0); // false
    复制代码

    6)特殊等式

    NaN和-0在相等比较时的表现有些特别。

    由于NaN和自身不相等,所以必须使用ES6中的Number.isNaN(..)。 而-0等于0(对于===也是如此),因此我们必须使用isNegZero(..)这样的工具函数。

    复制代码
    //特殊等式
    if (!Object.is) {
      Object.is = function(v1, v2) {
        // 判断是否是-0
        if (v1 === 0 && v2 === 0) {
          return 1 / v1 === 1 / v2;
        }
        // 判断是否是NaN
        if (v1 !== v1) {
          return v2 !== v2;
        }
        // 其他情况
        return v1 === v2;
      };
    }
    复制代码

    7)值和引用

    JavaScript引用指向的是值。如果一个值有10个引用,这些引用指向的都是同一个值,它们相互之间没有引用/指向关系。

    向函数传递值的时候,实际是将引用值的一个复本传递进去,不管是基本类型还是对象。

    复制代码
    //基本类型
    var a = 2;
    var b = a; // b是a的值的一个副本
    b++;
    a; // 2
    b; // 3
    
    //变量引用同一个值
    var c = [1, 2, 3];
    var d = c; // d是[1,2,3]的一个引用
    d.push(4);
    c; // [1,2,3,4]
    d; // [1,2,3,4]
    
    //变量引用不同的值
    var a = [1, 2, 3];
    var b = a;
    b = [4, 5, 6]; //给b重新赋值,引用新的值,不影响a的引用
    a; // [1,2,3]
    b; // [4,5,6]
    
    //函数内让参数重新引用值
    function foo2(x) {
      x.push(4);
      x; // [1,2,3,4]
      
      x = [4, 5, 6];// 然后重新引用新的值
      x.push(7);
      x; // [4,5,6,7]
    }
    var a = [1, 2, 3];
    //向函数传递a的时候,实际是将引用a的一个复本赋值给x,而a仍然指向[1,2,3]
    foo2(a);
    a; // 是[1,2,3,4],不是[4,5,6,7]
    复制代码

    上面的源码可以在此次浏览

    二、原生函数

    常用的原生函数有:String()、Number()、Boolean()、Array()、Object()、Function()、RegExp()、Date()、Error()、Symbol()。

    1)内部属性[[Class]]

    这个属性无法直接访问,一般通过Object.prototype.toString(..)来查看。

    //内部属性[[Class]]
    Object.prototype.toString.call([1, 2, 3]); // "[object Array]" 
    Object.prototype.toString.call(/regex-literal/i); // "[object RegExp]"
    //基本类型
    Object.prototype.toString.call(null); // "[object Null]"
    Object.prototype.toString.call(undefined); // "[object Undefined]"

    虽然Null()和Undefined()这样的原生构造函数并不存在,但是内部[[Class]]属性值仍然是"Null"和"Undefined"。

    基本类型值被各自的封装对象自动包装,所以它们的内部[[Class]]属性值分别为"String"、"Number"和"Boolean"。

    Object.prototype.toString.call("abc"); // "[object String]"
    Object.prototype.toString.call(42); // "[object Number]"
    Object.prototype.toString.call(true); // "[object Boolean]"

    2)封装对象包装

    由于基本类型值没有.length和.toString()这样的属性和方法,需要通过封装对象才能访问,此时JavaScript会自动为基本类型值包装(box或者wrap)一个封装对象:

    //封装对象
    var a = "abc";
    a.length; // 3
    a.toUpperCase(); // "ABC"

    如果想要自行封装基本类型值,可以使用 Object(..) 函数(不带 new 关键字)

    复制代码
    //自行封装基本类型
    var a = "abc";
    var b = new String(a);
    var c = Object(a);
    
    typeof a; // "string" 
    typeof b; // "object" 
    typeof c; // "object"
    b instanceof String; // true 
    c instanceof String; // true
    Object.prototype.toString.call(b); // "[object String]" 
    Object.prototype.toString.call( c ); // "[object String]"
    复制代码

    3)拆封

    如果想要得到封装对象中的基本类型值,可以使用valueOf()函数:

    复制代码
    //拆封
    var a = new String("abc");
    var b = new Number(42);
    var c = new Boolean(true);
    
    console.log(a.valueOf()); // "abc"
    console.log(b.valueOf()); // 42
    console.log(c.valueOf()); // true
    复制代码

    在需要用到封装对象中的基本类型值的地方会发生隐式拆封。

  • 相关阅读:
    golang生成树状菜单
    golang自定义某种类型时的打印输出
    【转】搭建自己的邮件服务器
    【转】【VSCode】golang的调试配置launch.json
    【转】Nvidia GeForce MX250 Lower-End Dedicated Graphics
    【转】Alertmanager高可用
    【转】Prometheus 和 Alertmanager实战配置
    YAML格式的语法
    golang写一个占用大内存的程序
    [转]TDengine常用命令及SQL
  • 原文地址:https://www.cnblogs.com/libin-1/p/6523169.html
Copyright © 2020-2023  润新知