美文网首页
JavaScript提升系列(四):数据类型

JavaScript提升系列(四):数据类型

作者: 拳战攻城师 | 来源:发表于2020-03-23 09:44 被阅读0次

    前言

    前方高能预警:本文中Number类型及其基础、硬核且无聊,导致大部分人觉得这些内容没什么用。如果你中途坚持不住,建议点赞,收藏后,改日再战。

    对于初次接触JavaScript的朋友来说,本文信息量略为丰富,建议收藏,多多复习,练习。

    如果你为了追求极致的学习速度,想知道JavaScript与C++/Java不同之处,请直接翻到文末小结部分。

    数据类型

    ECMAScript中有5种基本数据类型:Undefined, Null, Boolean, NumberString和一种复杂数据类型Object
    ECMAScript不支持任何创建自定义类型的机制,所有值最终都将是上述6种数据类型之一。

    typeof操作符

    对一个值使用typeof操作符,可能会返回下列某个字符串:

    • "undefined",变量未被初始化,或变量未被定义。
    • "boolean",布尔值。
    • "string",字符串。
    • "number",数值。
    • "object",对象或null
    • "function",函数。

    Undefined类型

    Undefined类型只有一个值,就是undefined
    在使用var声明变量但未对其进行初始化时,该值为undefined
    包含undefined值的变量和尚未定义的变量是不一样的,如下例:

    var message;   //该变量默认为undefined。
    
    //下面变量未被声明
    //var age; 
    
    alert(message);  //undefined
    alert(age);     //ReferenceError: age is not defined.
    

    迷惑的是,在使用typeof操作符时,两者的值都是undefined,如下例:

    alert(typeof message);  //"undefined"
    alert(typeof age);          //"undefined"
    

    所以,强烈推荐显式的初始化变量。这样,我们就可以知道被检测的变量的状态是没声明,而不是尚未初始化。**

    Null类型

    Null类型也只有一个值,就是null
    从逻辑角度来看,null值表示一个对象的空指针,事实上,这也就解释了为什么在使用typeof操作符检测null时,会返回"object"。如下例所示。

    var car = null;
    alert(typeof car);  //"object"
    

    如果定义的变量要用于保存对象的话,最好将该变量初始化为null这样只需要检查null值就可以知道相应的变量是否已经保存了一个变量引用。

    var car = null;
    if( car!=null ){
      //对car对象执行某些操作
    }
    

    需要注意的是,undefined的值是派生自null值的,因此ECMA-262规定对它们进行相等性测试时,必须返回true。

    alert( undefined==null );    //true
    

    无论在什么情况下都没必要把一个变量的值显式设置为undefined,这样可以有助于区分undefinednull

    Boolean类型

    Boolean类型是ECMAScript中使用最多的一种类型,该类型只有两个字面值truefalse(注意:truefalse是区分大小写的)
    ECMAScript中所有类型的值都可以通过Boolean()函数来转换为相应的等价值。

    var message = "Hello World!";
    alert(Boolean(message));    //true
    

    下表为各类数据类型与Boolean类型的转换规则。

    数据类型 转换为ture 转换为false
    Boolean true false
    String 任何非空字符串 ""
    Number 任何非零数字值(包括无穷大) 0和NaN
    Object 任何对象 null
    Undefined undefined

    Number类型

    最基本的字面值格式是十进制整数,如下:

    var intNum = 123;
    

    除十进制外,整数还可以通过八进制或十六进制的字面值来表示。

    八进制

    八进制字面值的第一位必须是零(0),然后是八进制数字序列(0~7)。如果字面值中的数值超出了范围,那么前导0将会被忽略,后面的数值按照十进制解析。如下例:

    var octalNum1 = 070;  //八进制的56
    var octalNum2 = 079;  //无效的八进制数值,解析为79
    var octalNum3 = 08;    //无效的八进制数据,解析为8
    

    八进制在严格模式下是无效的,会导致支持的JavaScript引擎抛出错误。

    十六进制

    十六进制的前两位必须是0x,后跟任何十六进制数字(0~9及A~F)。其中,A~F字母即可以大写,也可以小写。

    var hexNum1 = 0xA;  //十六进制的10
    var hexNum2 = 0x1f;  //十六进制的31
    

    在进行算数运算时,所有以八进制和十六进制表示的数值最终都将转换为十进制数值。

    浮点数值

    浮点数值,该数值中必须包含一个小数点,并且小数点后面至少得有一位数字。
    小数点前面可以省略整数,但不推荐。

    var floatNum1 = 1.1;
    var floatNum2 = 0.1;
    var floatNum3 = .1;    //有效,但不推荐。
    

    由于保存浮点整数需要的内存空间是保存整数的两倍,所以ECMAScript会不失时机的将浮点数值转换为整数值。

    var floatNum1 = 1.;      //小数点后面没有数字,解析为1。
    var floatNum2 = 10.0;  //整数,解析为10。
    

    对于极大或极小的值,可以使用e表示法(科学计数法)表示的浮点数表示。

    var floatNum1 = 3.125e7;  //3.125*10^7 = 31250000
    var floatNum2 = 3e-17;      //3*10^(-17) = 0.00000000000000003
    

    浮点数值的最高精度是17位小数,但在算术计算时,其精度远远不如整数。

    alert(0.1+0.2);       //0.30000000000000004
    alert(0.1+0.2==0.3);  //false
    

    数值范围

    ECMAScript能够表示最小的数值保存在Number.MIN_VALUE,大多数浏览器中,其值为5e-324
    ECMAScript能够表示最大的数值保存在Number.MAX_VALUE中,大多数浏览器中,其值为1.7976931348623157e+308

    当某次计算的结果得到了超出JavaScript数值范围的值时,这个数值会自动转换为Infinity值。
    当该值为正无穷时,得到的是Infinity值;该值为负无穷时,得到的是-Infinity值。

    当某次计算的值返回了正或负Infinity值时,该值无法继续参与下一次计算,因为Infinity不是能够参与计算的数值。
    我们可以通过isFinite()函数来判断一个数值是否是无穷。

    alert(isFinite(0));                     //false
    alert(isFinite(Number.MAX_VALUE+1));    //true
    

    NaN

    NaN,非数值,是一个特殊的数值,用于表示一个本来要返回数值的操作未返回数值的情况。例如:

    alert(1/0);    //NaN
    

    NaN本身有两个非比寻常的特点。

    • 任何涉及与NaN操作,结果都是NaN(好比0乘任何数都得0)
    • NaN不与任何数值相等,包括NaN自己。
    alert(0*NaN);        //NaN
    alert(0/NaN);        //NaN
    alert(0+NaN);       //NaN
    alert(0-NaN);        //NaN
    alert(NaN==NaN);  //false
    

    因此,ECMAScript定义了isNaN()函数,用来确定参数是否为NaN
    该函数接受到值后,会尝试将该值转换为数值,任何不能被转换为数值的值都会导致这个函数返回true。

    alert(isNaN(NaN));          //true
    alert(isNaN(0));               //false
    alert(isNaN("Hello"));      //true, "Hello"不能被转换为数值。
    alert(isNaN(isNaN(NaN)))  //false
    

    数值转换

    有三个函数,可以把非数值转换为数值。

    • Number(),将任何数据类型转换为整型数值。
    • parseInt(),将字符串转为整型数值。
    • parseFloat(), 将字符串转为浮点型数值。

    Number()转换规则如下:

    • Boolean类型,truefalse被转换为10
    • 数字类型,只是简单的传入和返回。
    • null,返回0
    • undefined,返回NaN
    • 字符串遵循以下规则:
      • 如果字符串中只包含数字,则将其转换为十进制数。
      • 如果字符串中包含有效的浮点数格式,则转换为相应的浮点数值。
      • 如果字符串中包含有效的16进制格式,则转换为相同大小的10进制数值。
      • 如果字符串为"",返回0。
      • 如果字符串中包含上述格式之外的字符,则转换为NaN
    • 如果是对象,则调用对象的valueOf()方法,然后依照前面的规则转换返回的值。如果转换的结果是NaN,则调用对象的toString()方法,然后再依照前面的规则转换返回的字符。
    var num1 = Number("1111");        //1111
    var num2 = Number(true);            //1
    var num3 = Number("");                //0
    var num4 = Number("123a");        //NaN,因为包含字母a
    var num5 = Number("0xf");            //15
    

    相比较Number()函数,parseInt()函转换规则就宽松多了,parseInt()函数在转换字符串时,更多的是看其是否符合数值模式。
    它会忽略字符串前面的空格,直至找到第一个非空格字符。
    如果第一个字符不是负号或数字,那么parseInt()函数会返回NaN
    如果第一个字符是数字,parseInt()函数会继续解析第二个字符,直到解析完成,或者遇到非数字字符。
    如果字符串以0x开头,parseInt()函数会将其当作16进制整数。

    var num1 = parseInt("           123");    //123
    var num2 = parseInt("123a");            //123
    var num3 = parseInt("");                    //NaN
    var num4 = parseInt("0xf");                //15
    var num5 = parseInt("07");                //ECMAScript3中返回56,ECMAScript5以上返回7
    

    在使用parseInt()函数解析八进制字面值数值时,ECMAScript3和ECMAScript5存在分歧,为了消除上述困惑,可以为这个函数提供第二个参数:转换时的基数。
    如果知道当前字符串是16进制,那么可以指定基数为16,例子如下:

    var num1 = parseInt("f",16);    //15
    var num2 = parseInt("70",8);    //56
    var num3 = parseInt("10",2);    //2
    

    不指定基数意味着让parseInt()函数决定如何解析输入的字符串,为了避免错误解析,强烈建议无论在什么情况下都明确指定基数。

    parseFloat()函数与parseInt()函数类似,也是从第一个字符开始解析每一个字符,而且也是一直解析到字符串末尾,或者解析遇到了一个无效的浮点数字符为止。
    parseFloat()函数会始终忽略前导的0。由于parseFloat()函数只解析10进制数,因此它没有第二个参数指定基数的用法。
    如果字符串包含的是一个可解析为整数的数,parseFloat()函数会返回整数。

    var num1 = parseFloat("1234abcd");          //1234,解析到整数值,返回整数1234
    var num2 = parseFloat("0xA");                    //0,遇到x无效字符,返回0
    var num3 = parseFloat("22.5");                  //22.5
    var num4 = parseFloat("22.34.5");              //22.34,遇到.无效字符,返回22.34
    var num5 = parseFloat("0908.5");                //908.5,忽略前导0,返回908.5
    var num6 = parseFloat("3.125e7");            //31250000
    

    String类型

    String类型用于表示零或多个16位Unicode组成的字符序列,即字符串。
    通常有两种表示方法。(ECMAScript6中,新增一种表示方法)

    var firstName = "Nicholas";
    var lastName = 'Zakas';
    

    单引号表示的字符串与双引号表示的字符串完全相同,但双引号开头必须双引号结尾,单引号开头必须单引号结尾。

    字面值常量

    String类型包含一些特殊的字符字面值,也叫转义序列,用于表示非打印字符,或其它用途的字符,这些字面值如下表所示:

    字面量 含义
    \n 换行
    \t 制表
    \b 空格
    \r 回车
    \f 进纸
    \\ 斜杠
    \' 单引号'
    \" 双引号"
    \xnn 以16进制代码nn表示字符,\x41表示"A"
    \unnnn 以十六进制代码nnnn表示一个Unicode字符,\u03a3表示希腊字母

    上述字符字面值可以出现在字符串中任意位置,而且也作为一个字符被解析。

    var text = "This is the letter sigma: \u03a3.";
    alert(text.length);      //28
    

    如果字符串中包含双字节字符,那么length属性可能不会精确返回字符串中字符的数目。

    字符串的特点

    ECMAScript中的字符串是不可变的,也就是说,字符串一旦创建,他们的值就不能改变。
    要改变某个变量保存的字符串,首先得先销毁原来的字符串,再用另一个新字符串填充该变量。

    var str = "Hello";
    str = str + " World!";    // Hello World!
    

    转换为字符串

    有两种方式可以将一个值转换为字符串:
    除了nullundefined之外,每个值都有的toString()函数。

    var x = 100;
    var xString = x.toString();  //  "100"
    var y = true;
    var yString = y.toString();  // "true"
    

    大多数情况下,toString()函数不必传递参数,但在调用数值的toString()函数时,可以传递一个参数:输出值的基数。

    var num = 10;
    var numString1 = num.toString();    // "10"
    var numString2 = num.toString(2);  // "1010"
    var numString3 = num.toString(8);  // "12"
    var numString4 = num.toString(10);  // "10"
    var numString5 = num.toString(16);  // "a"
    

    在不知道值是否为nullundefined时,还可以使用转型函数String(),这个函数能够将任何类型的值转换为字符串。
    String()函数遵循下列转换规则:

    • 如果值有toString()函数,则调用该方法,并返回相应的结果。
    • 如果值是null,则返回"null"
    • 如果值是undefined,则返回"undefined"
    var v1 = 123;
    var v2 = true;
    var v3 = null;
    var v4;
    alert(String(v1));  // "123"
    alert(String(v2));  // "true"
    alert(String(v3));  // ”null“
    alert(String(v4));  // "undefined"
    

    Object类型

    ECMAScript中的对象其实就是一组数据和功能的集合。对象可以通过执行new操作符后跟要创建的对象名称来创建。

    var o = new Object();
    

    这个语法与Java中创建对象的语法相似,但在ECMAScript中,如果不给构造函数传递参数,则可以省略后面的那对圆括号。(不推荐此做法)

    在ECMAScript中,Object类型是所有它的实例的基础,换句话说,Object类型所具有的任何属性和方法也同样存在更具体的对象中。

    Object的每个实例都有下列属性和方法。

    • Constructor,保存着用于创建当前对象的函数。
    • hasOwnProperty(propertyName),用于检查给定的属性在当前实例中是否存在,其中propertyName参数必须以字符串形式指定。
    • isPrototypeOf(object),用于检查传入的对象是否是另一个对象的原型。
    • propertyIsEnumerable(propertyName),用于检查给定的属性是否能使用for-in语句来枚举。
    • toLocaleString(),返回对象的字符串表示,该字符串与执行环境地区相对应。
    • toString(),返回对象的字符串表示。
    • valueOf(),返回对象的字符串,数值或布尔值表示。通常与toString()方法的返回值相同。

    从技术角度来说,ECMA-262中对象的行为不一定适用于JavaScript中的其他对象。浏览器中的对象,比如BOM和DOM中的对象,都属于宿主对象,因为它们是由宿主实现提供和定义的。

    总结

    本文总结分为如下三大部分,以下总结不知道原理的,评论区见。

    与C++/Java不同之处

    • JavaScript只有6种数据类型(Number, Boolean, Object, Undefined, Null, String),且不支持用户自定义类型。
    • JavaScript中当计算溢出时,结果会为正或负Infinity
    • JavaScript中有一个神奇的值NaN

    严格模式

    • 在严格模式下,不能定义以八进制为字面值表示整数,会导致引擎抛出错误。

    Effective小技巧

    • 强烈建议,定义变量时,显式的将其初始化。(为什么?)
    • 强烈建议,任何情况下,定义变量时,都不要将其初始化为undefined。(为什么?)
    • 强烈建议,定义要保存对象的变量时,将其初始化为null。(为什么?)
    • 强烈建议,使用parseInt()函数,而不是Number()函数。
    • 强烈建议,使用parseInt()函数时,明确指定基数。

    相关文章

      网友评论

          本文标题:JavaScript提升系列(四):数据类型

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