ECMAScriptJavaScript筑基篇(二)->JavaScript数据类型

说明

介绍JavaScript数据类型

目录

前言

参考来源

前人栽树,后台乘凉,本文参考了以下来源

停放技术要求

翻阅本文前,提出先读书以下小说

JavaScript的6种数据类型

var 变量 = 值; //其中只有两种类型,一种是基本类型(类似于常量数据),一种是引用类型(对象)                    

率先,大家要简明一点JavaScript的数据类型即为值的数据类型。JavaScript中有6种数据类型(5种基本数据类型,1种引用类型)

哪6种数据类型

  • 五种基本数据类型(其实也统称为基本型或原始型)

    undefined,null,number,boolean,string

  • 一种复杂数据类型(引用型)

    Object

undefined 类型

undefined型唯有一个值,即特殊的undefined。使用var申明变量但未对其加以起头化时,那个变量的值就就是undefined。例如

var a;
console.log(a===undefined);//true

null 类型

null型也只有一个值,即null,从逻辑角度来看,null值表示一个空指针(那也是
选取typeof操作符检测重临object的因由)。假诺定义的变量准备在今日用于保存对象,那么最好将该变量先河化为null而不是其余值。那样只要间接检测null值就足以精晓相应的变量是或不是早已保存了一个对象的引用了。

var a = null;
console.log(typeof a);//"object"

事实上,ECMAScript中,可以认为undefined值是派生自null值的,所以undefined==null不过undefined!==null

console.log(undefined==null);//true
console.log(undefined===null);//false

留神,一定要差别undefined和null的运用。一般的话,变量的值早先设置为undefined(记得别突显设置,由解释器默认设置即可)。而引用型对象的初始值一般可以显式的装置为null。或者可以如此敞亮undefined作为中央数据类型的变量的伊始值(默许设置),null作为引用类型的变量的开首值(显式设置)

boolean 类型

boolean型唯有七个字面值true,false。但是那八个值和数字值不是四回事,因而true不一定等于1,而false也不自然等于0。

要将一个值转为boolean型等价的值,有二种方案:

  • 一种是显式转换-调用类型转换函数Boolean()
  • 一种是自动转换-如if(value)中的value就会自动转载成为boolean值

各种型与boolean型之间值得转换关系如下表

数据类型 转换为true的值 转换为false的值
boolean true false
string 任何非空字符串 "" (空字符串)
bumber 任何非零数字值(包括无穷大) 0和NaN
undefined undefined
null null
Object 任何对象

number 类型

number类型用来代表整型和浮点数字,还有一种特有的数值(NaN-not a
number,这么些数值用于表示一个当然要回到数值的操作数未归来数值得情形-幸免抛出错误)。

诸如在其它语言中数值÷0都会促成错误,甘休运行,可是在JS中。0/0、NaN/0会回到NaN,其余数字/0会重返Infinity,不会报错。

任何涉及与NaN的操作都会重回NaN,JS有一个isNaN()函数,可以断定接受的参数是还是不是为NaN,或者参数转化为数字后是还是不是为NaN

console.log(NaN + 1); //NaN,任何涉及到NaN的操作都会返回NaN
console.log(NaN === NaN); //false,NaN与任何值都不相等,包括NaN本身
console.log(isNaN(NaN)); //true,是NaN
console.log(isNaN('10')); //false,被转为数字10
console.log(isNaN(true)); //false,被转为数字1
console.log(isNaN(null)); //false,被转为数字0
console.log(isNaN(undefined)); //true,返回NaN
console.log(isNaN('hello')); //true,无法转换为数字
console.log(0/0);//NaN,0/0返回NaN
console.log(NaN/0);//NaN,NaN/0返回NaN
console.log(1/0);//Infinity,其它数字/0返回Infinity
console.log('1'/0);//Infinity,'1'成功转为数字
console.log('1a'/0);//NaN,'1a'转为数字失败,变为NaN
console.log(Infinity/0);//Infinity,其它数字/0返回Infinity

留意:Infinity的品种是Number(不是基础数据类型)

有三种方法可以将非number类型的值转换为number类型

  • 一种是隐式转换,如进行(*、/)操作时,会自行其余项目标值转为number类型

    console.log("1"*2);//12
    console.log("1"/2);//0.5
    console.log("1a"/2);//NaN
    
  • 一种是显得转换-调用Number()、parseInt()、parseFloat()方法转换

    Number()函数的转换规则如下:(引自参考来源)

    • 即使是boolean值,true和false将分别被互换为1和0
    • 倘诺是数字值,只是简单的扩散和再次来到
    • 如果是null值,返回0
    • 如果是undefined,返回NaN
    • 一旦是字符串,坚守下列规则:
      • 若是字符串中只蕴涵数字,则将其转移为十进制数值,即”1“会化为1,”123“会成为123,而”011“会成为11(前导的0被忽略)
      • 假诺字符串中包罗有效的浮点格式,如”1.1“,则将其转移为相应的浮点数(同样,也会忽视前导0)
      • 比方字符串中隐含有效的十六进制格式,例如”0xf“,则将其转移为同一大小的十进制整数值
      • 只要字符串是空的,则将其转移为0
      • 如若字符串中隐含除了上述格式之外的字符,则将其更换为NaN
    • 假定是目的,则调用对象的valueOf()方法,然后根据前边的规则转换再次回到的值。假若转换的结果是NaN,则调用对象的toString()方法,然后再相继按照前边的条条框框转换再次回到的字符串值。

      console.log(Number(''));//0
      console.log(Number('a'));//NaN
      console.log(Number(true));//1
      console.log(Number('001'));//1
      console.log(Number('001.1'));//1.1
      console.log(Number('0xf'));//15
      console.log(Number('000xf'));//NaN
      var a = {};
      console.log(Number(a));//NaN
      a.toString = function(){return 2};
      console.log(Number(a));//2
      a.valueOf = function(){return 1};
      console.log(Number(a));//1                              
      
parseInt()常常用于将其它类型值转化为整形。parseInt转换与Number()有区别,具体规则如下

-   **parseInt(value,radius)有两个参数,第一个参数是需要转换的值,第二个参数是转换进制(该值介于
    2 ~ 36 之间。如果该参数小于 2 或者大于 36,则 parseInt() 将返回
    NaN。),如果不传(或值为0),默认以10为基数(如果value以 “0x” 或
    “0X” 开头,将以 16 为基数)**
-   **注意在第二个参数默认的情况下,如果需要转换的string值以0开头,如'070',有一些环境中,会自动转化为8进制56,有一些环境中会自动转化为10进制70。所以为了统一效果,我们在转换为10进制时,会将第二个参数传10**
-   **parseInt转换示例**

        console.log(parseInt(''));//NaN
        console.log(parseInt('a'));//NaN
        console.log(parseInt('1234blue'));//1234
        console.log(parseInt(true));//NaN
        console.log(parseInt('070'));//70,但是有一些环境中会自动转换为8进制56
        console.log(parseInt('070',8));//56
        console.log(parseInt('001.1'));//1
        console.log(parseInt('0xf'));//15,16进制
        console.log(parseInt('AF',16));//175,16进制
        console.log(parseInt('AF'));//NaN
        console.log(parseInt('000xf'));//0
        var a = {};
        console.log(parseInt(a));//NaN
        a.toString = function(){return 2};
        console.log(parseInt(a));//2
        a.valueOf = function(){return 1};
        console.log(parseInt(a));//2                            


parseFloat()转换规则基本与parseInt()一致,只有如下不同点

-   **parseFloat()遇到浮动数据时,浮点有效(但是只有第一个.有效),如"10.1"会被转为10.1;'10.1.1'会被转为10.1**
-   **parseFloat()只会默认处理为10进制,而且会忽略字符串前面的0,所以不会有在默认情况下转为8进制的情况**
-   **示例**

        console.log(parseFloat('1234blue'));//1234
        console.log(parseFloat('1234blue',2));//1234
        console.log(parseFloat('0xA'));//0
        console.log(parseFloat('10.1'));//10.1
        console.log(parseFloat('10.1.1'));//10.1
        console.log(parseFloat('010'));//10                             


由于Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是parseInt()函数-需注意最好第二个参数传10,处理浮点数时更常用parseFloat()

另外注意,浮点数直接的计算存在误差,所以两个浮点数无法用"="进行判断

    var a=10.2;
    var b= 10.1;
    console.log(a - b === 0.1);//false
    console.log(a - 10.1 === 0.1);//false,实际是0.09999999999999964
    console.log(a - 0.1 === 10.1);//true                        

string 类型

string类型用于表示由零或多个16位Unicode字符组成的字符连串,即字符串。字符串可以由单引号(‘)或双引号(“)表示。任何字符串的尺寸都得以透过拜访其length属性取得。

要把一个值转换为一个字符串有二种艺术。

  • 首先种是利用大约每个值都有的toString()方法(除去null和undefined没有)
    • toString(radius)有一个参数-基数,当需求toString的值为number时,参数能够生效(可以转移为对应进制输出,如10.toString(8)输出为12)
  • 其次种是隐式转换,比如字符串+
    number(null,undefined,object等),会默许转为字符串(如果前面相加的是object对象,会回来object对象的toString或valueOf值)
  • 其二种是通过转移函数String(),String()转换规则如下
    • 比方值有toString()方法,则调用该办法(没有参数)并赶回相应的结果(注意,valueOf()方法行不通)
    • 若果值是null,则赶回”null”
    • 借使值是undefined,则赶回”undefined“
  • 示例

    var a = 10;
    var b = '10'
    var c = {};
    console.log(a.toString());//10
    console.log(a.toString(8));//12
    console.log(b.toString(8));//10,字符串基数没用
    console.log(String(c));//[object Object]
    console.log(c);//[object Object]
    console.log(c + '1');//[object Object]1
    
    c.valueOf = function(){return 2};
    console.log(String(c));//[object Object]
    console.log(c);//[object Object],valueOf没用
    console.log(c + '1');//21,隐式转换时,valueOf起作用了
    
    c.toString = function(){return 2};
    console.log(String(c));//2
    console.log(c);//2,toString起作用了
    
    console.log(String(null));//"null",null和undefined可以String()输出
    console.log(null.toString());//报错,null和undefined不能toString                        
    

复杂 类型

复杂 类型即引用型,也就是大家常说的JS对象(蕴含常见的object型对象和function型对象)

目的实际就是一组数据和意义的聚集。对象可以通过实施new操作符后跟要创制的靶子类型的称谓来成立。而成立Object的实例并为其添加属性和(或)方法,就足以创设自定义对象。如

var o = new Object();//创建一个新的自定义对象{}          

也就是说,除去基本项目,剩余的就是引用型(包涵内置对象,自定义对象等)都是基于Object举办进行的

Object的各类实例都兼备下列属性和措施:

  • constructor——保存着用于制造当前目的的函数
  • hasOwnProperty(propertyName)——用于检查给定的习性在当前目的实例中(而不是在实例的原型中)是或不是留存。其中,作为参数的属性名(propertyName)必须以字符串方式指定(例如:o.hasOwnProperty(“name”))
  • isPrototypeOf(object)——用于检查传入的对象是或不是是另一个目标的原型
  • propertyIsEnumerable(propertyName)——用于检查给定的属性是或不是可以运用for-in语句来枚举
  • toString()——重返对象的字符串表示
  • valueOf()——重返对象的字符串、数值或布尔值表示。平日与toString()方法的重回值相同。

参考
JS原型和原型链的明亮

基本型和引用型的不等

基本型和引用型最大的不一样就是互相的囤积形式各异,如图:

ECMAScript 1

  • 也就是说,上图中,即使变量1的值变为102,实际中栈内存中的101是不会变的,只是在栈内存中新开辟出一处,用来存放在102以此常量。然后将变量1指向102。

  • 而变量2由于栈内存中存放的是指针,实际执行的是堆内存中的数目,所以变量2的值是足以任由改的(堆内存中的数码可以更改)

至于数据类型的有的常见疑难

为什么typeof null === ‘object’

其一问题有不少人提议过,因为按理说,null作为JS的五大主导数据类型之一,那么typeof
null 为和会===object呢?那与ECMAScript的历史原因有关。原因如下:

  • JS中的五大要旨数据类型,除了null外,其他的花色存放在栈区的都是常量值(如undefined存放的是undefined值,number类型可以存放0,1,2…之类)
  • 与其它四种档次相同,null的值也是存放在栈区的,而且也唯有一个值null。而刚好从逻辑上觉得那是一个空对象的指针(机器码NULL空指针),所以typeof时会再次回到object。
    (具体原因如下,引自搜狐同名回答)

    • JS类型值是存在32 BIT 单元里,32位有1-3位表示TYPE
      TAG,其他位代表真实值
    • 而代表object的标记位正好是低三位都是0 (000: object. The data
      is a reference to an object.)
    • 而js 里的null 是机器码NULL空指针, (0x00 is most
      platforms).所以空指针引用 加上
      对象标记依然0,最后反映的门类或者object..
    • 那也就是为啥Number(null)===0吗…
  • 曾有提案尝试修复typeof ===
    ‘null’,不过被驳回了(如在V8引擎中会导致大量问题)

string,String,object,Object,function,Function的关系

请区分Object,Function,String与object,function,string。

  • Object,Fucntion,String是JS内置对象(都是引用型),object,function,string是typeof检查项目后的重返值。
  • 诚如情况下,大家把后边的object,undefined,function等誉为对应值的品类(null用typeof
    无法识其余,别的函数对象回来function)。
  • 为此到了这一步,应该是有所的引用类型typeof都回到object的。但是在引用类型中,有一个比较特其余系列”fucntion”。它的面世导致了引用类型中函数对象typeof再次来到’function’。

    切切实实参考:
    function类型与object类型的分别

  • 今昔又回去了初期的数据类型划分的时候了

    • JS中的基本数据类型有五种:undefined,null,number,boolean,string
    • JS中的引用类型中蕴藏三种:object、function(fucntion类型是Function对象typeof检测后的重回值,Function对象是基于Object拓展的)
    • JS中有一些放置对象:Object,Function,String。那几个目的用typeof重返值都是function。可是new
      Object()出来的新对象的typeof重临值就是object(除了new
      Function()重返function以外)
    • 故而实际上那一个品种名称都是分裂人温馨定义出来的,不要被他们限制。
    比如有的人会说JS中有7中类型:5中基本数据类型和object与function(但其实我们这这里就将后面两种以前算成引用型了)

    或者用一句话总结更为合适:"JS中有对象,每一个对象都有一个自己的类型"。就好比每一个动物都有属于自己的类型一样(人类,猴子...)。另外基本类型可以认为是一个不会改变的对象(便于理解)

    至于为什么基本类型明明不是引用型,却能像引用型一样去使用一些基本数据操作(如toFixed,toString等)。请参考
    [基本数据类型为什么能够使用toString等操作](http://www.cnblogs.com/dailc/p/5971244.html#basicKnowledge_3_8)

至于String类型与string类型的问题

JavaScript中,基本项目有string,number等等,复杂类型中也展开有String,Number等等。那么那两者的界别是什么样啊?如下图,简单描述了中央项目中的string与复杂类型中的String的分裂。

也就是说,string类型都是坐落栈内存中的(类似于常量),如若string类型的变量的值改为另一个string,那么栈内存中原有的string并从未成形,只不过是在栈内存中新开拓出一个string,然后改变变量的引用而已

而Strign的型的栈内存中唯有指针,指向堆内存的数码。所以只要值进行了转移,是会直接修改堆内存中的多少内容,而栈内存中的指针并不会变。

function类型与object类型的区分

本条一个知识点也是许几个人可疑的地方,明明只有一种复杂对象Object,但怎么有些函数类型的typeof
再次回到function,其他对象回来 object呢?

  • 简易点可以如此领悟:Object,Function,String等都是JavaScript内置的函数对象,typeof是获取函数对象的花色,所以回来fucntion。而new
    Object()、new
    String()等是布局出一个新的对象,所以typeof重临object。而new
    Fucntion()构造处理的依然是一个函数对象,所以回来fucntion

    Function是最顶层的构造器。它构造了系统中有着的目的,包蕴用户自定义对象,系统内置对象,甚至席卷它自已。

  • 至于Object和Function可以如此敞亮

    null是天地之始,然后null生了Object,Object是万物之母。然后Object有一个性质constructor,恰巧可以回来function的值,所以typeof
    Object为function。然后Function是基于Object派生的。Function.prototype._proto_指向Object.prototype。(Function.constructor也返回function值)

  • 一经要深刻掌握,需求对JS中的原型和原型链有一定驾驭

    参考
    JS原型和原型链的通晓

  • 示例

               function a(){};
                var b = function(){};
                var c = new Function();
                var d = new Object();
                var e = new String();
                var f = new Date();
                console.log(typeof a);//function
                console.log(typeof b);//function
                console.log(typeof c);//function
                console.log(typeof Function);//function
                console.log(typeof Object);//function
                console.log(typeof d);//object
                console.log(typeof String);//function
                console.log(typeof e);//object
                console.log(typeof Date);//function
                console.log(typeof f);//object  
    
                console.log(Object instanceof Function);//true
                console.log(Function instanceof Object);//true
                console.log(new Object() instanceof Object);//true
                console.log(new Object() instanceof Function);//false
                console.log(new Function() instanceof Function);//true
                console.log(new Function() instanceof Object);//true
    
                function Foo(){};
                var foo = new Foo();
                console.log(foo instanceof Foo);//true
                console.log(foo instanceof Function);//false
                console.log(foo instanceof Object);//true
                console.log(Foo instanceof Function);//true
                console.log(Foo instanceof Object);//true
    

==和===的区别

==和===在JS中都有相比的意趣,可是两者兼有很大的例外,两者分别如下:

  • 对于string,number,boolean等基础简单类型而言,==和===是有分其他

    因为不相同品类的值相比,==会将相比值转换为同样类型的值后
    在看值是或不是等于。===的话会先判断项目,如果类型分裂,结果就是不等。

  • 对此引用类型而言,==和===是一直不区分的

    因为那类值得相比较都是“指针地址”比较,分裂的值,肯定为false

  • 对于基础项目和引用类型比较而言,==和===是有分其他

    对此==会将复杂类型转换为根基项目,进行值比较,对于===,由于品种分裂,直接为false

  • 示例

    var a = 1;
    var b = true;
    console.log(a == b); //true,转换为同一类型后值相等
    console.log(a === b); //false,先比较类型不能,直接为false
    
    var a = {
        'test': '1'
    };
    var b = {
        'test': '1'
    };
    console.log(a == b); //false,比较指针地址,不等
    console.log(a === b); //false,比较指针地址,不等
    
    var a = '11';
    var b = new String('11');
    console.log(a == b); //true,将高级类型String转化为基础类型,值相等
    console.log(a === b); //false,因为类型不同,直接为false                     
    

typeof的作用

JS的变量的值是高枕无忧类型的(弱类型),可以保存任何类型的多少,JS内置的typeof可以检查给定变量的数据类型,可能的再次回到值如下:

  • undefined:undefined类型
  • boolean:boolean类型
  • string:string类型
  • number:number类型
  • object:null类型或者其余的引用型(object,去除function)
  • function:这些值是函数对象,引用类型中的特殊种类(可以认为引用型中除了了function就是object)

console.log(typeof 'test'); //'string'
console.log(typeof 101); //'number'
console.log(typeof true); //'boolean'
console.log(typeof undefined); //'undefined'
console.log(typeof null); //'object'
console.log(typeof function() {}); //'function'
console.log(typeof {}); //object
console.log(typeof new Date()); //object                

instanceof的作用

instanceof用于判断一个变量是或不是是某个对象的实例,紧如果判定某个构造函数的prototype属性是或不是留存另一个要检核查象的原型链上。

  • Instanceof可以断定内置的对象类型(基于Obejct对象开展的,如Array,Date等)。
  • 可以看清自定义对象类型,如下述中的Child和Parent
  • 不过不可能判定简单类型(因为本质是由此原型来判定,可是不难类型只是一个常量,并不是援引对象)

           //识别内置对象 - Array, Date等
            console.log([] instanceof Array); //true
            console.log(new String('11') instanceof String); //true
            console.log('11'
                instanceof String); //false,因为11是简单类型
            //识别自定义对象类型以及父子类型
            function Parent(x) {
                this.x = x;
            }

            function Child(x, y) {
                Parent.call(this, x);
                this.y = y;
            }
            //将Child的原型指向Parent,表明继承关系,此时Child的构造变为了Parent的构造
            Child.prototype = new Parent();
            //然后将构造函数换为Child自己的
            Child.prototype.constructor = Child;
            console.log(Child.prototype.constructor); //输出构造函数是Child自己的
            var person = new Child(1, 2);
            console.log(person.x + ',' + person.y); //1,2
            console.log(person instanceof Child); //true
            console.log(person instanceof Parent); //true

            //不能识别简单类型,因为instanceof后面只能是基于Object对象拓展的类型
            console.log(101 instanceof number); //报错,number is not defined             

Object.prototype.toString的作用

Object.prototype.toString的存在重大是为了缓解typeof和instanceof的欠缺,比如typeof不能辨别内置类型(Array
Date等),而instanceof不能分辨简单类型。所以才有了这一个。

Object.prototype.toString可以辨认5种简易类型,以及所有放手类型(Array.Date等部分放手类型),不过力不从心分辨自定义对象类型

/**
             * @description 通过Object.prototype.toString来判断传入对象类别
             * @param {Object} obj
             */
            function type(obj) {
                //slice的作用,例如本来返回[object number],slice筛选出number
                return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
            }
            console.log(type(1)); //number
            console.log(type('1')); //string
            console.log(type(true)); //boolean
            console.log(type(undefined)); //undefined
            console.log(type(null)); //null
            console.log(type(new Date())); //date
            console.log(type([])); //array
            console.log(type({})); //object
            function Test(a) {
                this.a = a;
            }
            console.log(type(new Test('1'))); //object,自定义类别只能识别为object               

骨干数据类型为何可以使用toString等操作

面前说到JS中有基本类型和引用类型(对象类型、复杂类型各类说法都行)。请留意两者是有本质区其余。

  • 着力项目标值举行toString操作时,并不是用自身举行操作的,而是有接近与“装箱”、“拆箱”的操作

    var a = 10.1;
    console.log(a.toFixed(2));//10.10,临时构建了个Number对象进行操作,操作完后销毁了
    
    a.foo = 'test';
    console.log(a.foo); // undefined,因为a的值并不是一个对象,无法绑定属性                     
    
上述代码中,对基本类型的`a`进行`a.xx`操作时,会在内部临时创建一个对应的包装类型(比如number类型对应Number类型)的临时对象。并把对基本类型的操作代理到对这个临时对象身上,使得对基本类型的属性访问看起来像对象一样。但是在操作完成后,临时对象就扔掉了,下次再访问时,会重新建立临时对象,当然对之前的临时对象的修改都不会有效了。