彩世界平台-彩世界时时app-彩世界开奖app苹果下载

热门关键词: 彩世界平台,彩世界时时app,彩世界开奖app苹果下载

您的位置:彩世界平台 > 新闻动态 > 你不知道的JavaScript(中卷)|强制类型转换

你不知道的JavaScript(中卷)|强制类型转换

发布时间:2019-09-03 21:50编辑:新闻动态浏览(135)

    我们都知道,无论是用那种程序设计语言,通过强制类型转换函数 ,每个函数都可以强制将一个表达式转换成某种特定数据类型。下面介绍Javascript中的强制类型转换函数。

    值类型转换
    将值从一种类型转换为另一种类型通常称为类型转换,这是显示的情况;隐式的情况称为强制类型转换。JavaScript中的强制类型转换总是返回标量基本类型值,如字符串、数字和布尔值,不会返回对象和函数。我们介绍过“封装”,就是为标量基本类型值封装一个相应类型的对象,但这并非严格意义上的强制类型转换。
    也可以这样来区分:类型转换发生在静态类型语言的编译阶段,而强制类型转换则发生在动态类型语言的运行时。

    Javascript (ECMA Script)是一种弱类型的语言.这并不意味着它没有数据类型,只是变量或者Javascript对象属性不需要一个特定类型的值分配给它或者它始终使用相同的值.Javascript中的变量同样支持自由类型转换成为适用(或者要求)的内容以便于使用.

    var a = 42;
    var b = a + ""; // 隐式强制类型转换
    var c = String( a ); // 显式强制类型转换
    

    弱类型的Javascript不会按照程序员的愿望从实际的变量类型到所需要的数据类型转换,例如一个非常常见的错误,在浏览器脚本中,从表单控件中获取用户将要输入的一个数值类型的变量与另一个数值变量的和.

    对变量b而言,强制类型转换是隐式的;由于+运算符的其中一个操作数是字符串,所以是字符串拼接操作,结果是数字42被强制类型转换为相应的字符串“42”。

    因为变量类型在表单控件中是字符串类型(计时字符串序列包含一个数字)这种尝试将会添加那个字符串到变量,即使这些值碰巧是一些数字,结果在第二个变量将会被转换为字符串类型,在最后只会把从表单控件中得到的变量添加到第一个字符串末尾。

    ToString
    它负责处理非字符串到字符串的强制类型转换。基本类型值的字符串化规则为:null转换为“null”,undefined转换为“undefined”,true转换为“true”。数字的字符串化则遵循通用规则。不过那些极小和极大的数字使用指数形式:

    所以强制类型转换还是比较重要的,下面看一下它的几个强制转换的函数:

    // 1.07 连续乘以七个 1000
    var a = 1.07 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000 * 1000;
    // 七个1000一共21位数字
    a.toString(); // "1.07e21"
    
    1. Boolean(value):把值转换成Boolean类型;

    2. Nnumber(value):把值转换成数字整型或浮点数);

    3. String(value):把值转换成字符串。

    对普通对象来说,除非自行定义,否则toString()(Object.prototype.toString())返回内部属性[[Class]]的值,如“[object Object]”。
    数组的默认toString()方法经过了重新定义,将所有单元字符串化以后再用“,”连接起来:

    我们先来看Boolean():在要转换的值为“至少有一字符的字符串”、“非0的数字”或“对象”,那么Boolean()将返回true,如果要转换的值为“空字符串”、“数字0”、“undefined”,“null”这些话,那么Boolean()会返回false。你可以用以下代码来测试

    var a = [1,2,3];
    a.toString(); // "1,2,3"
    

    以下为引用的内容:

    JSON字符串化
    工具函数JSON.stringify(..)在将JSON对象序列化为字符串时也用到了ToString。
    对于大多数简单值来说,JSON字符串和toString()的效果基本相同,只不过序列化的结果总是字符串:

    var t1 = Boolean("");//返回false,空字符串  var t2 = Boolean("s");//返回true,非空字符串  var t3 = Boolean(0);//返回false,数字0  var t3 = Boolean(1),t4 = Boolean(-1);//返回true,非0数字  var t5 = Boolean(null),t6 = Boolean(undefined);//返回false  var t7 = Boolean(new Object());//返回true,对象 
    
    JSON.stringify( 42 ); // "42"
    JSON.stringify( "42" ); // ""42"" (含有双引号的字符串)
    JSON.stringify( null ); // "null"
    JSON.stringify( true ); // "true"
    

    再来看看Number():

    所有安全的JSON值都可以使用JSON.stringify(..)字符串化。安全的JSON值是指你能够呈现为有效JSON格式的值。
    JSON.stringify(..)在对象中遇到undefined、function和symbol时会自动将其忽略,在数组中则会返回null(以保证单元位置不变)。

    Number()与parseInt()和parseFloat()类似,它们区别在于Number()转换是整个值,而parseInt()和parseFloat()则可以只转换开头的数字部分,例如:Number("1.2.3"),Number("123abc")会返回NaN,而parseInt("1.2.3")返回1、parseInt("123abc")返回123、parseFloat("1.2.3")返回1.2、parseFloat("123abc")返回123。Number()会先判断要转换的值能否被完整的转换,然后再判断是调用parseInt()或parseFloat()。下面列了一些值调用Number()之后的结果:

    JSON.stringify(undefined); // undefined
    JSON.stringify(function () { }); // undefined
    JSON.stringify(
        [1, undefined, function () { }, 4]
    ); // "[1,null,null,4]"
    JSON.stringify(
        { a: 2, b: function () { } }
    ); // "{"a":2}"
    

    以下为引用的内容:

    对包含循环引用的对象执行JSON.stringify(..)会出错。
    我们可以向JSON.stringify(..)传递一个可选参数replacer,它可以是数组或者函数,用来指定对象序列化过程中哪些属性应该被处理,哪些应该被排除。
    如果replacer是一个数组,那么它必须是一个字符串数组,其中包含序列化要处理的对象的属性名称,除此之外其他的属性则被忽略。
    如果replacer是一个函数,它会对对象本身调用一次,然后对对象中的每个属性各调用一次,每次传递两个参数,键和值。如果要忽略某个键就返回undefined,否则返回指定的值。

    Number(false) 0  Number(true) 1  Number(undefined) NaN  Number(null) 0  Number("1.2") 1.2  Number("12") 12  Number("1.2.3") NaN  Number(new Object()) NaN  Number(123) 123 
    
    var a = {
        b: 42,
        c: "42",
        d: [1, 2, 3]
    };
    JSON.stringify(a, ["b", "c"]); // "{"b":42,"c":"42"}"
    JSON.stringify(a, function (k, v) {
        if (k !== "c") return v;
    });
        // "{"b":42,"d":[1,2,3]}"
    

    最后是String():这个以比较简单了,它可以把所有类型的数据转换成字符串,如:String(false)---"false"、String(1)---"1"。它和toString()方法有些不同,区别在于:

    JSON.string还有一个可选参数space,用来指定输出的缩进格式。space为正整数时是指定每一级缩进的字符数,它还可以是字符串,此时最前面的十个字符被用于每一级的缩进:

    以下为引用的内容:

    var a = {
        b: 42,
        c: "42",
        d: [1, 2, 3]
    };
    JSON.stringify(a, null, 3);
    // "{
    // "b": 42,
    // "c": "42",
    // "d": [
    // 1,
    // 2,
    // 3
    // ]
    // }"
    JSON.stringify( a, null, "-----" );
    // "{
    // -----"b": 42,
    // -----"c": "42",
    // -----"d": [
    // ----------1,
    // ----------2,
    // ----------3
    // -----]
    // }"
    
    var t1 = null;  var t2 = String(t1);//t2的值 "null"  var t3 = t1.toString();//这里会报错  var t4;  var t5 = String(t4);//t5的值 "undefined"  var t6 = t4.toString();//这里会报错 
    

    请记住,JSON.stringify(..)并不是强制类型转换。在这里介绍是因为它涉及ToString强制类型转换,具体表现在以下两点:
    (1)字符串、数字、布尔值和null的JSON.stringify(..)规则与ToString基本相同。
    (2)如果传递给JSON.stringify(..)的对象中定义了toJSON()方法,那么该方法会在字符串化前调用,以便将对象转化为安全的JSON值。

    建议大家看看这一篇,介绍的是C++中的强制类型转换函数,《浅谈C++中强制类型转换函数》。希望对你有帮助。

    ToNumber
    有时候我们需要将非数字值当做数字来使用,比如数学运算。为此ES5规范定义了抽象操作ToNumber。
    其中true转换为1,false转换为0。undefined转换为NaN,null转换为0。
    ToNumber对字符串的处理基本遵循数字常量的相关规则/语法。处理失败时返回NaN(处理数字常量是把你时会产生语法错误)。不同之处是ToNumber对以0开头的十六进制数并不按十六进制处理(而是按十进制)。
    对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。
    为了将值转换为相应的基本类型值,抽象操作ToPromitive会首先(通过内部操作DefaultValue)检查该值是否有valueOf()方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用toString()的返回值(如果存在)来进行强制类型转换。
    如果valueOf()和toString()均不返回基本类型值,会产生TypeError错误。
    从ES5开始,使用Object.create(null)创建的对象[[Prototype]]属性为null,并且没有valueIOf()和toString()方法,因此无法进行强制类型转换。

    强制类型转换函数 ,每个函数都可以强制将一个表达式转换成某种特定数据类型。下面介...

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

    假值
    JavaScript中的值可以分为以下两类:
    (1)可以被强制类型转换为false的值
    (2)其他(被强制类型转换为true的值)
    以下这些是假值:

    • undefined
    • null
    • false
    • +0、-0和NaN
    • “”

    假值的布尔强制类型转换结果为false。
    从逻辑上说,假值列表以外的都应该是真值。但JavaScript规范对此并没有明确定义,只是给出了一些示例,例如规定所有的对象都是真值,我们可以理解为假值列表意外的值都是真值。

    2、假值对象
    这个标题似乎有点自相矛盾。前面讲过规范规定所有的对象都是真值,怎么还会有假值对象呢?
    浏览器在某些情况下,在常规JavaScript语法基础上自己创建了一些外表值,这些就是“假值对象”。
    假值对象看起来和普通对象并无二致(都有属性,等等),但将它们强制类型转换为布尔值时结果为false。
    最常见的例子是document.all,它是一个类数组对象,包含了页面上的所有元素,由DOM(而不是JavaScript引擎)提供给JavaScript程序使用。它以前曾是一个真正意义上的对象,布尔强制类型转换结果为true,不过现在它是一个假值对象。
    document.all并不是一个标准用法,早就被废止了。
    那为什么它要是假值呢?因为我们经常通过将document.all强制类型转换为布尔值(比如if语句中)来判断浏览器是否是老版本的IE。IE自诞生之日起就始终遵循浏览器标准,较其他浏览器更为有力地推动了Web的发展。
    if(document.all){/it's IE/}依然存在于许多程序中,也许会一直存在下去,这对IE的用户体验来说不是一件好事。

    3、真值
    真值就是假值列表之外的值。

    var a = "false";
    var b = "0";
    var c = "''";
    var d = Boolean( a && b && c );
    d;//true
    
    var a = []; // 空数组——是真值还是假值?
    var b = {}; // 空对象——是真值还是假值?
    var c = function(){}; // 空函数——是真值还是假值?
    var d = Boolean( a && b && c );
    d;
    

    d依然是true。还是同样的道理,[],{}和function(){}都不在假值列表中,因此它们都是真值。

    字符串和数字之间的显式转换

    var a = 42;
    var b = String( a );
    var c = "3.14";
    var d = Number( c );
    b; // "42"
    d; // 3.14
    

    除了String(..)和Number(..)以外,还有其他方法可以实现字符串和数字之间的显式转换:

    var a = 42;
    var b = a.toString();
    var c = "3.14";
    var d = +c;
    b; // "42"
    d; // 3.14
    

    1、日期显式转换为数字
    一元运算符+的另一个常见用途是将日期(Date)对象强制类型转换为数字,返回结果为Unix时间戳i,以微妙为单位:

    var d = new Date( "Mon, 18 Aug 2014 08:53:06 CDT" );
    +d; // 1408369986000
    

    我们常用下面的方法来获得当前的时间戳,例如:

    var timestamp = +new Date();
    

    JavaScript有有一处奇特的语法,即构造函数没有参数时可以不用带()。于是我们可能会碰到var timestamp = +new Date;这样的写法。这样能否提高代码可读性还存在争议,因为这仅用于new fn(),对一般的函数用fn()并不适用。

    2、奇特的~运算符

    0 | -0; // 0
    0 | NaN; // 0
    0 | Infinity; // 0
    0 | -Infinity; // 0
    

    indexOf(..)不仅能够得到子字符串的位置,还可以用来检查字符串中是否包含指定的子字符串,相当于一个条件判断。例如:

    var a = "Hello World";
    if (a.indexOf("lo") >= 0) { // true
        // 找到匹配!
    }
    if (a.indexOf("lo") != -1) { // true
        // 找到匹配!
    }
    if (a.indexOf("ol") < 0) { // true
        // 没有找到匹配!
    }
    if (a.indexOf("ol") == -1) { // true
        // 没有找到匹配!
    }
    

    = 0 和== -1这样的写法不是很好,称为“抽象渗漏”,意思是在代码中暴露了底层的实现细节,这里是指用-1作为失败时的返回值,这些细节应该被屏蔽掉。
    现在我们终于明白有什么用处了!和indexOf()一起可以将结果强制类型转换(实际上仅仅是转换)为真/假值:

    var a = "Hello World";
    ~a.indexOf("lo"); // -4 <-- 真值!
    if (~a.indexOf("lo")) { // true
        // 找到匹配!
    }
    ~a.indexOf("ol"); // 0 <-- 假值!
    !~a.indexOf("ol"); // true
    if (!~a.indexOf("ol")) { // true
        // 没有找到匹配!
    }
    

    如果indexOf(..)返回-1,~将其转换为假值0,其他情况一律转换为真值。

    3、字位截除
    一些开发人员使用~~来截除数字值的小树部分,以为这和Math.floor(..)的效果一样,实际上并非如此。

    Math.floor( -49.6 ); // -50
    ~~-49.6; // -49
    

    显式解析数字字符串
    解析字符串中的数字和将字符串强制类型转换为数字的返回结果都是数字。但解析和转换两者之间还是有明显的差别。

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

    解析允许字符串中含有非数字字符,解析按从做到右的顺序,如果遇到非数字字符就停止。而转换不允许出现非数字字符,否则会失败并返回NaN。
    ES5自己的parseInt(..)有一个坑导致了很多bug。即如果没有第二个参数来指定转换的基数,parseInt(..)会根据字符串的第一个字符来自行决定基数。
    如果第一个字符是x或x,则转换为十六进制数字。如果是0,则转换为八进制数字。
    以x和x开头的十六进制相对来说还不太容易搞错,而八进制则不然。例如:

    var hour = parseInt(selectedHour.value);
    var minute = parseInt(selectedMinute.value);
    console.log(
        "The time you selected was: " + hour + ":" + minute
    );
    

    上面的代码看似没有问题,但是当小时为08、分钟为09时,结果是0:0,因为8和9都不是有效的八进制数。
    将第二个参数设置为10,即可避免这个问题:

    var hour = parseInt( selectedHour.value, 10 );
    var minute = parseInt( selectedMiniute.value, 10 );
    

    从ES5开始parseInt(..)默认转换为十进制数,除非另外指定。如果你的代码需要在ES5之前的环境运行,请记得将第二个参数设置为10。

    解析非字符串
    曾经有人发帖吐槽过parseInt(..)的一个坑:

    parseInt( 1/0, 19 ); // 18
    

    parseInt(1/0,19)实际上是parseInt("Infinity",19)。第一个字符是“I”,以19为基数时值为18。第二个字符“n”不是一个有效的数字字符,解析到此为止,和“42px”中的“p”一样。
    此外还有一些看起来奇怪但实际上解释得通的例子:

    parseInt( 0.000008 ); // 0 ("0" 来自于 "0.000008")
    parseInt( 0.0000008 ); // 8 ("8" 来自于 "8e-7")
    parseInt( false, 16 ); // 250 ("fa" 来自于 "false")
    parseInt( parseInt, 16 ); // 15 ("f" 来自于 "function..")
    parseInt( "0x10" ); // 16
    parseInt( "103", 2 ); // 2
    

    显式转换为布尔值
    与前面的String(..)和Number(..)一样,Boolean(..)(不带new)是显式的ToBoolean强制类型转换:

    var a = "0";
    var b = [];
    var c = {};
    var d = "";
    var e = 0;
    var f = null;
    var g;
    Boolean( a ); // true
    Boolean( b ); // true
    Boolean( c ); // true
    Boolean( d ); // false
    Boolean( e ); // false
    Boolean( f ); // false
    Boolean( g ); // false
    

    和前面讲过的+类似,一元运算符!显式地将值强制类型转换为布尔值。但是它同时还将真值反转为假值(或者将假值反转为真值)。所以显式强制类型转换为布尔值最常用的方法是!!,因为第二个!会将结果反转会原值:

    var a = "0";
    var b = [];
    var c = {};
    var d = "";
    var e = 0;
    var f = null;
    var g;
    !!a; // true
    !!b; // true
    !!c; // true
    !!d; // false
    !!e; // false
    !!f; // false
    !!g; // false
    

    在if(..)..这样的布尔值上下文中,如果没有使用Boolean(..)和!!,就会自动隐式地进行ToBoolean转换。建议使用Boolean(..)和!!来进行显式转换以便让代码更清晰易读。

    字符串和数字之间的隐式强制类型转换
    通过重载,+运算符即能用于数字加法,也能用于字符串拼接:

    var a = "42";
    var b = "0";
    var c = 42;
    var d = 0;
    a + b; // "420"
    c + d; // 42
    

    这里为什么会得到“420”和42两个不同的结果呢?通常的理解是,因为某一个或者两个操作数都是字符串,所以+执行的是字符串拼接操作。这样解释只对了一半,实际情况要复杂得多。

    var a = [1,2];
    var b = [3,4];
    a + b; // "1,23,4"
    

    a和b都不是字符串,但是它们都被强制转换为字符串然后进行拼接。
    根据ES5规范,如果某个操作数是字符串或者能够通过以下步骤转换为字符串的话,+将进行拼接操作。如果其中一个操作数是对象(包括数组),则首先对其调用ToPrimitive抽象操作,该抽象操作在调用[[DefaultValue]],以数字作为上下文。
    你或许注意到这与ToNumber抽象操作处理对象的方式一样。因为数组的valueOf()操作无法得到简单基本类型值,于是它转而调用toString()。因此上例子中的两个数组编程了"1,2"和“3,4”。+将它们拼接后返回“1,23,4”。
    简单来说就是,如果+的其中一个操作数是字符串(或者通过以上步骤可以得到字符串),则执行字符串拼接,否则执行数字加法。

    有一个坑常常被提到,即[]+{}和{}和[],它们返回不同的结果,分别是“[object Object]”和0。

    我们可以将数字和字符串“”相+来将其转换为字符串:

    var a = 42;
    var b = a + "";
    b; // "42"
    

    再来看看从字符串强制类型转换为数字的情况:

    var a = "3.14";
    var b = a - 0;
    b; // 3.14
    

    对象的-操作与+类似:

    var a = [3];
    var b = [1];
    a - b; // 2
    

    为了执行减法运算,a和b都需要被转换为数字,它们首先被转换为字符串(通过toString()),然后再转换为数字。

    布尔值到数字的隐式强制类型转换
    在将某些复杂的布尔逻辑转换为数字加法的时候,隐式强制类型转换能派上大用场。当然这种情况并不多见,属于特殊情况特殊处理。

    function onlyOne(a, b, c) {
        return !!((a && !b && !c) ||
            (!a && b && !c) || (!a && !b && c));
    }
    var a = true;
    var b = false;
    onlyOne(a, b, b); // true
    onlyOne(b, a, b); // true
    onlyOne(a, b, a); // false
    

    以上代码如果有多个参数时(4个、5个,甚至20个),用上面的代码就很难处理了。这是就可以使用从布尔值到数字(0或1)的强制类型转换:

    本文由彩世界平台发布于新闻动态,转载请注明出处:你不知道的JavaScript(中卷)|强制类型转换

    关键词: