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))的结果。

  • 相关阅读:
    「七天自制PHP框架」第四天:模型关联
    「七天自制PHP框架」第三天:PHP实现的设计模式
    「七天自制PHP框架」第二天:模型与数据库
    一个例子简要说明include和require的区别
    解读Laravel,看PHP如何实现Facade?
    Laravel是怎么实现autoload的?
    Laravel表单提交
    Laravel的console使用方法
    PHP控制反转(IOC)和依赖注入(DI)
    PHP解耦的三重境界(浅谈服务容器)
  • 原文地址:https://www.cnblogs.com/y8932809/p/6198316.html
Copyright © 2011-2022 走看看