JS中的数据类型

一、JS中的数据类型

基本类型

分为以下六种:

  1. string(字符串)
  2. boolean(布尔值)
  3. number(数字)
  4. symbol(符号)
  5. null(空值)
  6. undefined(未定义)

说明:

  1. symbol是ES6中新增的数据类型,symbol 表示独一无二的值,通过 Symbol 函数调用生成,由于生成的 symbol 值为原始类型,所以 Symbol 函数不能使用 new 调用;

  2. null 和 undefined 通常被认为是特殊值,这两种类型的值唯一,就是其本身

  3. 简单数据类型不可以有自定义属性和方法的,但string/number/boolean却有对应的包装类型String/Number/Boolean,

var str = 'hello'; 
str.substr(0,1); // h 
// 执行到这一句,后台依然会偷偷的干这些事
{   
    var _str = new String('hello'); // 找到基本包装对象,new一个和字符串值相同的对象
    _str.substr(0,1);  // 通过这个对象找到了包装对象下的方法并调用,输出结果
    _str =null; //释放这个对象
}

特别注意boolean类型的计算:

console.log(new Boolean(false) && true) //true
console.log(Boolean(false) && true) //false
console.log(false && true) //false
console.log(1 + true) // 2
console.log('1' + true) // 1true
console.log(1 + '2' + true) //12true

对象类型

对象类型也叫引用类型,array和function是对象的子类型。对象在逻辑上是属性的无序集合,是存放各种值的容器。对象值存储的是引用地址,对象值是可变的。

每个对象都有一个 toString() 方法和一个valueOf()方法

Object.prototype.toString()

当对象被表示为文本值时或者当以期望字符串的方式引用对象时,该方法被自动调用。

Object.prototype.valueOf()

当把对象转换成原始类型的值时(如强制转换和运算)会自行调用。

var temp = function() {
}
temp.valueOf = function() {
    return 2;
}
temp.toString = function() {
    return 'hello';
}
console.log(temp); //hello
console.log(2 * temp); //4

二、JS类型转换

弱类型

JavaScript 是弱类型语言,JavaScript 声明变量时并没有预先确定类型,变量的类型由其值所决定,由于这种“不需要预先确定类型”特性给我们带来了便利,同时带来了类型转换的复杂度。例如:

String({})          // '[object Object]'
String([1,[2,3]])   // 1,2,3

强制转换规则

1、内部函数:toPrimitive(input,preferedType?)

input是输入的值,preferedType是期望转换的类型,它可以是字符串,也可以是数字。

  1. 如果转换的类型是number,会执行以下步骤:
  • 如果input是原始值,直接返回这个值;

  • 否则,如果input是对象,调用input.valueOf(),如果结果是原始值,返回结果;

  • 否则,调用input.toString()。如果结果是原始值,返回结果;

  • 否则,抛出错误。

  1. 如果转换的类型是String,2和3会交换执行,即先执行toString()方法。

  2. 省略preferedType参数,此时日期会被认为是字符串,而其他的值会被当做Number

2、强制转换函数:String()、Number() 、Boolean()

String 转换规则

String(null)                 //"null"
String(undefined)            //"undefined"
String(true)                 //"true"
String(1)                    // '1'
String(-1)                   // '-1'
String(0)                    // '0'
String(-0)                   // '0'
String(Math.pow(1000,10))    // '1e+30'
String(1E+400)               // 'Infinity'
String(-Infinity)            // '-Infinity'
String({})                      // '[object Object]'
String([1,[2,[3,4]],['a'])       // '1,2,3,4,a'
String(function (){return 0})  //function({return 0})

注意:

  • 数字转换遵循通用规则,溢出将以指数形式或者无穷大
  • 数组的toString()方法会返回一个以逗号分割的字符串,不论嵌套的层次
  • 函数的toString()方法返回函数本身
  • 对象的toString()方法返回"[object Object]",前一个object标记基础类型,后一个Object标记子类型

Number转换规则:

Number(null);       //0
Number(undefined);  //NaN
Number(true);	      //1
Number(false);      //0
Number('1');        //1
Number('a');        //NaN

注意:

  • undefined 转换为 NaN
  • 字符串转换时遵循数字常量规则,转换失败返回 NaN

Boolean转换规则

除了下述5 个值转换结果为 false,其他全部为 true

  1. undefined
  2. null
  3. 0、+0、-0
  4. NaN
  5. ''(空字符串)
Boolean(undefined) // false
Boolean(null)      // false
Boolean(0)         // false
Boolean(NaN)       // false
Boolean('')        // false

Boolean({})        // true
Boolean([])        // true
Boolean(new Boolean(false)) // true

注意:

  • new Boolean(false)也是true

自动转换规则

1、什么时候自动转换为string

  • 字符串的自动转换,主要发生在字符串的加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。
'2' + 1              // '21'
'2' + true           // "2true"
'2' + undefined      // "2undefined"
null + '2'           // "null2"
'2' + function (){}  // "2function (){}"
['test',1] + '2'     // test,12
var obj = {
    toString:function(){
        return 'a'
    }
}
console.log(obj+'2') //a2

2、什么时候自动转换为Number类型

  • 在有加法运算符但是无String类型的时候,都会优先转换为Number类型

    true + 0 // 1
    true + true // 2
    true + null //1
    true + undefined //NaN
    
  • 除了加法运算符,其他运算符转换为Number类型

    '5' - '2'      // 3
    '5' * '2'      // 10
    false - 1      // -1
    '5' * []       // 0
    false / '5'    // 0
    'abc' - 1      // NaN
    null + 1       // 1
    undefined + 1  // NaN
    +'abc'         // NaN
    +true          // 1
    
  • 双等号==即抽象相等,会优先转换Number进行比较

var obj1 = {
    valueOf:function(){
        return '1'
    }
}
1 == obj1  //true
[] == ![]  //true
//[]作为对象ToPrimitive得到 ''  
//![]作为boolean转换得到0 
//'' == 0 
//转换为 0==0 //true
3 == true // false
'0' == false //true
//存在boolean,会将boolean转换为1或者0
NaN == NaN // false
{} == {}   // false
'2' == 2   // true
'a' == 'a' // true
//对于ToPrimitive为Number得到NaN后会判断原始类型是不是string
//如果相等返回ture,否则NaN的比较返回false

什么时候转换Boolean类型

  • 使用否定运算符
  • if() , while()、三元运算符判断时

三、js中的数据类型判断

typeof

typeof 'hello'     // 'string'
typeof true        // 'boolean'
typeof 10          // 'number'
typeof Symbol()    // 'symbol'
typeof null        // 'object' 无法判定是否为 null
typeof undefined   // 'undefined'

typeof {}           // 'object'
typeof []           // 'object'
typeof(() => {})    // 'function'

注意:

  1. null 的判定有误差,得到的结果是object,原因是在第一代javascipt设计中,数值是以32字节存储的,由标志位(1~3个字节)和数值组成。其中000标志为对象,所以Object.prototype.__proto__的值为null,反推是typeof null的值为object,

  2. 数组得到的结果是object

instanceof

通过 instanceof 操作符也可以对对象类型进行判定,其原理就是测试构造函数的 prototype 是否出现在被检测对象的原型链上。

[] instanceof Array            // true
({}) instanceof Object         // true
(()=>{}) instanceof Function   // true

但是instanceof 也不是万能的。 在数组上依旧存在误区,原因是 Array.prototype.**proto** === Object.prototype

let arr = []
arr instanceof Array    // true
arr instanceof Object   // true

Object.prototype.toString()

Object.prototype.toString.call({})              // '[object Object]'
Object.prototype.toString.call([])              // '[object Array]'
Object.prototype.toString.call(() => {})        // '[object Function]'
Object.prototype.toString.call('hello')         // '[object String]'
Object.prototype.toString.call(1)               // '[object Number]'
Object.prototype.toString.call(true)            // '[object Boolean]'
Object.prototype.toString.call(Symbol())        // '[object Symbol]'
Object.prototype.toString.call(null)            // '[object Null]'
Object.prototype.toString.call(undefined)       // '[object Undefined]'

Object.prototype.toString.call(new Date())      // '[object Date]'
Object.prototype.toString.call(JSON)            // '[object JSON]'
Object.prototype.toString.call(new Set())       // '[object Set]'

function Person() {}
var person = new Person();
Object.prototype.toString.call(person);         // "[object Object]"

我可以发现该方法在传入任何类型的值都能返回对应准确的对象类型。虽然简单明了,但需要注意以下几点:

  1. Object.prototype.toString()本身是允许被修改的,所以Object.prototype.toString()这个方法的应用都是假设toString()方法未被修改为前提的。
  2. 只有原生的js会返回内部属性[class],其余自定义的对象返回Object

四、其他注意点

NaN 的问题

NaN 是一个全局对象的属性,是一种特殊的Number类型。返回NaN的情况:

  1. 无穷大除以无穷大

  2. 给任意负数做开方运算

  3. 算数运算符与不是数字或无法转换为数字的操作数一起使用

  4. 字符串解析成数字

Infinity / Infinity;   // 无穷大除以无穷大
Math.sqrt(-1);         // 给任意负数做开方运算
'a' - 1;               // 算数运算符与不是数字或无法转换为数字的操作数一起使用
undefined + 1          // NaN
parseInt('a');         // 字符串解析成数字
+'abc'                 // NaN

toString()和String()的区别

  1. toString()可以将数据都转为字符串,但是null和undefined不可以转换。

    console.log(null.toString())
    //报错 TypeError: Cannot read property 'toString' of null
    
    console.log(undefined.toString())
    //报错 TypeError: Cannot read property 'toString' of undefined
    
  2. toString()括号中可以写数字,代表进制

(18).toString(2); //'10010'

posted @ 2019-12-17 13:14  linzj  阅读(1853)  评论(0编辑  收藏  举报