zoukankan      html  css  js  c++  java
  • 原生函数和强制类型装换

      var a = new String("abc");
      console.log(typeof a); //是Object,而不是string

    使用new String("abc"); 创建的是字符串 abc 的封装对象,而不是基本类型值"abc"。

    封装对象

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

     var a = "abc";
     console.log(a.length);

    注意:如果需要频繁的用到.length这样的属性和方法,那么从一开始就创建一个封装对象也许更方便,但需要注意的是,事实并非如此,因为浏览器已经为这些常用的方法做了性能优化。直接使用封装对象来提前优化,反而会降低执行效率。

     var a = new Boolean(false);
            if (!a) {
                console.log("aaaa"); //永远不会执行到这里
            }

    为false创建一个封装对象,然而该对象的真是是truthy,所有总是返回返回true,如果想要自行封装基本类型值,可以使用object函数。

    拆封

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

     var a = new String("abc");
     console.log(a.valueOf());//abc

    日期Date

    创建日期对象必须使用new Date() Date可以带参数用来指定日期和时间,而不带参数的话,则使用当前的日期和时间。

    强制类型装换

    强制类型转换分为隐式转换和显示转换,这两种转换的区别是根据你对程序的理解来定义的。例如:

     var a = 42;
     var b = a + "";//隐式转换
     var c = String(a);//显示转换

    如果你对a+""理解的话,那么这行代码对你来说也是显式转换。

    ToString方法

    基本类型字符串化规则为:null转换为"null",undefined转换为"undefined" true转换为"true",数字的字符串化则最需通用规则。

    对普通对象来说,除非自行定义,否则tostring返回内部属性Class的值,如:[object Object]

    JSON字符串化

    JSON.stringify在对象中遇到undefined、function、和symbol时会自动将其忽略。(连同属性一起忽略,例如:JSON.stringify({'a':1,'b':2,c:undefined}); 结果为:"{"a":1,"b":2}")

    replacer

    我们可以向JSON.stringify方法传递一个可选参数replacer,可以是数组或者函数,用来指定对象序列号过程中那些属性应该被处理或排除,如果replacer是一个数组,那么它必须是一个字符串数组

    其中包含序列化要处理的对象的属性名称,除此之外的属性将被忽略。

    如果replacer是一个函数,它会对对象本身调用一次,然后对对象的每个属性各调用一次,每次传递两个参数,建和值,如果要忽略某个键就返回undefined,否则返回指定的值。

    例如:

      console.log(JSON.stringify(a, ["b", "c"])); //{"b":42,"c":"42"}
            console.log(JSON.stringify(a, function (k, v) { //{"b":42,"d":[1,2,3]}
                if (k != "c") {
                    return v;
                }
            }));

    tonumber

    tonumber方法,其中true转换为1,false转为0,undefined转换为NaN,null转换为0

    在转换时,先检查是否有valueOf方法,如果有并且返回基本类型值,就使用该值进行强制类型转换,如果没有就使用tostring的返回值来进行强制类型转换。如果valueOf和tostring均不返回基本类型值,会产生typeerror错误。(使用object.crete(null)创建的对象属性为null,并且没有这两个方法)

      var a = {
                valueOf: function () {
                    return "43";
                }
            }
            var b = {
                toString: function () {
                    return "43";
                }
            }
            var c = [4, 3];
            c.toString = function () {
                return this.join("");
            }
    
            console.log(Number(a)); //43
            console.log(Number(b)); //43
            console.log(Number(c)); //43
            console.log(Number("")); //0
            console.log(Number([])); //0
            console.log(Number(["abc"])); //NaN

    ToBoolean

    我们常误以为数值1和0分别等同于true和false,在有些语言中可能是这样,但在JavaScript中布尔值和数字是不一样的,虽然我们可以将1强制转换为true,0转换为false,反之亦然,但它们并不是一回事。

    下面这些是可以转换为false的值:

    undefined

    null

    false

    +0、-0、NaN

    ""

    我们可以理解为除了以上转换为假值外,其他的都是真值

    例如:

            var a = "false";
            var b = "0";
            var c = "''"
            var d = [];
            var e = {};
            var f = function () { };
            console.log(Boolean(a)); //true
            console.log(Boolean(b));//true
            console.log(Boolean(c));//true
            console.log(Boolean(d));//true
            console.log(Boolean(e));//true
            console.log(Boolean(f));//true

    真值可以无限长,所以无法一一列举,这里只能以假值列表作为参考。

    显式强制转换

    +运算符

     var a = "3.14";
     console.log(+a);//3.14

    直接转换为数值类型而非数字假发运算,也不是字符串拼接。

    var a = "3.14";
    var d = 5 + +a;
    console.log(+d);//8.14

    这里需要注意两个+号的问题,如果中间不添加空格的话,那么可能会被按照 ++自增来运算。

    var d = new Date();
    console.log(+d); //1482134335608
    var d = +new Date();
    console.log(d); //1482134335609

    日期直接转为毫秒数。

    不过这样的写法可能在可读性上不是太好,并不推荐使用强制转换来得到毫秒数,所以可以有以下这几种写法,得到毫秒数:

            var timestamp = new Date().getTime();
            console.log(timestamp);//1482134515222
            var timestamp = (new Date()).getTime();
            console.log(timestamp);//1482134515222
            var timestamp = (new Date).getTime();
            console.log(timestamp);//1482134515222
            var timestamp = Date.now();
            console.log(timestamp);//1482134515222 推荐这种写法  

    ~运算符

    ~表示字位操作 “非”的相关枪支转换。

    ~x大致等同于-(x+1)。例如:

    console.log(~42);//-43

    这里需要注意的是,在-(x+1)中,唯一能够得到0的x值是-1,这个-1是一个稍为值,也就是被赋予了特殊含义的值。程序中一般用大于等于0的值来表示成功,-1表示失败。例如indexOf方法。

    那么这种>=0或者==-1的写法不是很好,这种代码被称为“抽象渗漏”,意思是在代码中暴露了底层的实现细节。这里是指用-1作为失败时返回的值,这些细节应该被屏蔽掉。

    例如:

         var a = "hello";
            if (~a.indexOf("lo")) {
                console.log("true");
            }
            if (!~a.indexOf("li")) {
                console.log("false");
            }

    使用这种方法会比>=0更简洁。

    ~~字位截除

         console.log(Math.floor(-49.6)); //-50
            console.log(~~-49.6); //-49 优先级更高
            console.log(-49.6|0); //-49 优先级低

    解析数字字符串

    Number()和parseInt()方法的区别:

         var a = "42";
            var b = "42px";
            console.log(Number(a)); //42
            console.log(parseInt(a));//42
            console.log(Number(b)); //NaN
            console.log(parseInt(b));//42

    可以看到parseint方法是执行到非不可转换为数字的字符时,停止转换,然后返回前面的值,而number方法则是要求整体必须都可以进行转换,才返回,否则返回NaN。

    parseint方法的执行过程:

    var a = {
                toString: function () {
                    return "48";
                }
            }
            console.log(parseInt(a));//48

    可以看到,parseInt方法先将参数转换为字符串再进行解析。

    !!布尔值转换

            var a = 0;
            console.log(!!a);//false

    隐式强制转换

    +运算符

    当有+运算符左右两端存在字符串时,那么会进行字符串连接,否则会进行加法运算。这是一般的情况下,但还有一种情况:

         var a = [1, 2];
            var b = [3, 4];
            console.log(a + b);//1,23,4

    a和b都不是字符串,这里为何会进行拼接呢,这是因为在进行转换时,会先调用数组的valueOf方法,然而数组的valueOf操作无法得到简单的基本类型,所以转而调用tostring方法,这样返回两个字符串后,进行拼接。

    a+""和String之间有一个席位的差别需要注意,a+""会调用valueof方法,然后通过tostring转为字符串,而String方法,会直接调用tostring方法。

      var a = {
                valueOf: function () { return 42 },
                toString: function () { return 4}
            }
            console.log(a + "");//42
            console.log(String(a));//4

    ||和&&

    在JavaScript中,它们被称为选择器运算符更恰当。因为和其他语言不同,它们返回的并不是布尔值。

    它们返回的是两个操作数中的一个(且仅一个),例如:

         var a = 42;
            var b = "abc";
            var c = null;
            console.log(a || b); //42
            console.log(a && b); //42
            console.log(c || b); //42
            console.log(c && b); //null

    可以看出,它们返回的是两个操作数中的一个,而非布尔值。

    可以换一个角度来理解:

    a||b 可以理解为:

    a?a:b

    a&&b可以理解为:

    a?b:a;

    下面是一个常见的用法:

    a=a||hello;

    还有一种方法并不常见,一般在压缩工具中常见,即:

    var a=43;
    a&&foo();

    这种被称为短路,也就是只有a在被定义时,才执行foo方法。

    当它们在if中使用时,其实是由if对最后的结果进行了强制类型转换。如:

     var a = 42;
            var b = "abc";
            if (a && b) {
                console.log(true); //true
            }

    也相当于:

      var a = 42;
            var b = "abc";
            if (!!a && !!b) {
                console.log(true); //true
            }

    ==和===运算符

    我们常见的对它们区别的解释为:==是检查值是否相等,而===是检查值和类型是否相等。

    这种解释还不够准确和全面,正确的解释为:==允许在相等比较重进行强制类型转换,而===不允许。

    根据第一种解释,我们可以列举为===似乎做的事比==更多,因为它还要检查类型,而第二种则正好相反。

    ==在比较两个不同类的值会发生隐式强制转换,会将其中之一或两者转换为相同的类型,再进行比较。

    例如:

         var a = 42;
            var b = "42";
            console.log(a == b); //true
            console.log(a === b);//false

    那么到底是将字符串转换为数值,还是将数值转换为字符串呢,具体的转换规则如下:

    如果type(x)是数字,type(y)是字符串,则返回x==ToNumber(y)的结果

    如果type(x)是字符串,type(y)是数字,那么则返回ToNumber(x)==y的结果

    ==最容易出错的一个地方是true和false与其他类型直接的比较:

         var a = "42";
            var b = true;
            console.log(a == b); //false

    我们都知道"42"是一个真值,那么为什么==的结果不是true呢,看一下规范:

    如果type(x)是布尔类型,则返回ToNumber(x)==y的结果

    如果type(y)是布尔类型,则返回x==ToNumber(y)的结果

    所以在这里,根据规范,先将true转换为1进行比较,变成"42"==1,然而类型仍然不同,在进行转换,"42"被转换为42变成42==1,所以为false。

    建议无论何时都不要使用 ==true 或者 ==false

    在==中 null和undefined是相当的,也就是说只判断 ==null就可以把undefined的情况也判断进去了。

    最特殊的情况:

     var i = 2;
            Number.prototype.valueOf = function () {
                return i++;
            }
            var a = new Number(42);
            if (a == 2 && a == 3) {
                console.log(true);//true
            }

    可以看到,判断条件为true,所以最好不要修改内置原型。

    所以==会在不经意间就进行了隐式转换,特别需要注意的两点:

    如果两边的值中有true或者false,千万不要使用==

    如果两边的值有[]、""或者0尽量不要使用==

    这时应该使用ongoing===来避免这些不经意间的错误。

    抽象关系比较

    一般来说比较对象时,会将对象转换为字符串,然后对字母进行比较,比较常见的是"123">"13"为false。但是有几种特殊的情况,如:

            var a = { b: 42 };
            var b = { b: 43 };
            console.log(a < b); //false
            console.log(a == b);//false
            console.log(a > b);//false
            console.log(a <= b);//true
            console.log(a >= b);//true

    这里需要注意的是,为什么a<b和a==b都为false,那么a<=b为什么为true?

    因为根据规范,a<=b被处理为a>b然后将结果反转。因为a>b 的结果为false,那么反转的结果为true。

    实际上JavaScript在处理>=时,是按照不大于的意思进行处理的,即(!(a<b))的结果。

  • 相关阅读:
    智器SmartQ T7实体店试用体验
    BI笔记之SSAS库Process的几种方案
    PowerTip of the Day from powershell.com上周汇总(八)
    PowerTip of the Day2010071420100716 summary
    PowerTip of the Day from powershell.com上周汇总(十)
    PowerTip of the Day from powershell.com上周汇总(六)
    重新整理Cellset转Datatable
    自动加密web.config配置节批处理
    与DotNet数据对象结合的自定义数据对象设计 (二) 数据集合与DataTable
    在VS2003中以ClassLibrary工程的方式管理Web工程.
  • 原文地址:https://www.cnblogs.com/y8932809/p/6198316.html
Copyright © 2011-2022 走看看