JavaScript基础篇(一):数据类型

279

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情

在学习JavaScript过程中数据类型是必不可少的一环,今天我们来看看JavaScript中有哪些数据类型吧。

ECMAScript语言类型

ECMAScript语言类型是分为Undefined、Null、Boolean、String、Number、Symbol、BigInt 和 Object的,也就是我们常说的值类型和引用类型。

Undefined 类型

Undefined 类型只有一个值就是undefined,一些变量没有被赋值,那么他就是undefined

Null类型

Null 类型只有一个值就是null

Undefined和Null的区别?

  1. undefined表示未定义,我们声明了一个变量但没给他赋值,或者访问了一个不存在的属性;null表示他是一个空值(空值也是有值)。
  2. undefined是一个全局的属性,可以对他赋值,但是被不会修改,因为他是不可配置的,null是一个关键字,不能被赋值。

Boolean类型

Boolean类型表示有两个值的逻辑实体true、false

String类型

JavaScript中的字符串类型表示文本数据,它包含0个或多个16位无符号整数值的的“元素”,在字符串中的每个元素占据了字符串的位置。第一个元素的索引为 0,下一个是索引 1,依此类推。字符串的长度是它的元素的数量。

StringIndexof

StringIndexof(string, serachValue, fromIndex)接受三个参数,用来查找字符串中是否有指定的字符,没有就返回-1,具体步骤如下:

  1. string断言成字符串,如果不是字符串类型就会直接报错
  2. serachValue会被转换成字符串
  3. fromIndex接受一个非负整数,否则会对其进行转换,能被转成数字的转成数字('1' => 1),否则都是0,负数也是0(或者是被忽略掉,只有转换后是非负整数才会生效)
  4. 定义一个变量len,他是字符串string的长度
  5. 判断serachValue是不是空字符串,并且fromIndex ≤ len,那么就返回fromIndex
  6. 定义一个变量searchLen其长度为serachValue的长度
  7. 定义一个变量i,从fromIndex开始,到i ≤ len-searchLen结束,每次遍历 i + searchLen长度的字符串,找到了就返回i
  8. 没找到返回-1

Symbol类型

符号(Symbols)类型是唯一不可修改的原始值,并且可以用来作为对象的键(key)

Number类型

Number类型和BigInt类型都是数字类型。数字类型是一种以IEE754为标准的双精度64位二进制格式的值,从 -(2^53 -1)2^53 - 1 之间的数字,还有+0、-0、NaN、+Infinity、-Infinity

要检查值是否大于或小于 ±Infinity,你可以使用常量 Number.MAX_VALUENumber.MIN_VALUE

从 ECMAScript 2015 开始,除了 Number.MAX_SAFE_INTEGERNumber.MIN_SAFE_INTEGER,你还可以通过 Number.isSafeInteger() 来检查值是否在双精度浮点数的取值范围内。

超出这个范围,JavaScript 中的整数将不再安全,该值将表示为与该值近似的双精度浮点数。

BigInt类型

可以表示任意精度的整数。使用 BigInt,您可以安全地存储和操作大整数,甚至可以超过数字类型的安全整数限制。

BigInt 是通过在整数末尾附加字母 n 或调用构造函数来创建的。

BigInt 不能与数字相互运算。否则,将抛出 TypeError

如何判断数据类型

typeof 操作符

typeof 操作符是一个一元运算符,返回一个字符串,表示未经计算的操作数的类型。他可以判断基础数据类型,对于引用类型都是object,不能准确判断,其中有两个特例,对于null会被判断为object,函数类型可以被准确判断出来是funciton

数据类型结果
Undefined"undefined"
Boolean"boolean"
Number"number"
String"string"
Symbol"symbol"
BigInt"bigint"
Null"object'
Function"funciton"
Object"object"
其他引用类型"object"

那么为什么null会被判断为object呢? 答:不同的对象在底层都表示为二进制, 在 JavaScript 中二进制前三位都为 0 的话会被判断为 object 类型, null 的二进制表示是全 0, 自然前三位也是 0, 所以执行 typeof 时会返回“object”。

instanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。

// object为实例对象,constructor为构造函数
object instanceof constructor

instanceof可以判断引用数据类型,但判断不了基本数据类型,只能判断基本数据类型的包装类型。

function instanceOf(proto, Ctor) {
    if ((typeof proto !== 'object' || proto === null) && typeof proto !== 'function') return false;

    let leftProto = Object.getPrototypeOf(proto);
    const rightProto = Ctor.prototype;
    while (leftProto) {
        if (leftProto === rightProto) return true;
        leftProto = Object.getPrototypeOf(leftProto);
    }
    return false
}

Object.prototype.toString()

Object.prototype.toString方法也是可以用来判断数据类型的,他会返回一个字符串"[object Class]"Class类似该数据类型的构造函数。他可以准确地判断出给个数据类型。简单举例如下:

Object.prototype.toString.call({})       // "[object Object]"
Object.prototype.toString.call([])  // "[object Array]"
Object.prototype.toString.call(1)    // "[object Number]"
Object.prototype.toString.call('1')  // "[object String]"
Object.prototype.toString.call(true)  // "[object Boolean]"
// ...

三种区别

方法基本数据类型引用数据类型注意
typeofNaN...
instanceof多窗口、右操作数必须是函数或class
toString小心内置原型
isPrototypeOf小心null和undefined
等比较特殊对象

instanceof和isPrototypeOf有什么不同?

  1. isPrototypeOf() 方法用于测试一个对象是否存在于另一个对象的原型链上prototypeObj.isPrototypeOf(object)
  2. instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

实现一个判断常见数据类型判断的方法

/**
 * 数据类型判断通用方法
 */
const getType = (obj) => {
    if (obj == null) return obj + '';
    return (typeof obj === 'object' || typeof obj === 'funciton')
                ? (Object.prototype.toString.call(obj).toLocaleLowerCase().slice(8, -1) || 'object')
                : typeof obj;
}

数据类型转换

ECMAScript语言会根据需要进行隐式的类型转换,而BigInt没有隐式转换,必须显示的调用他来转换成其他类型。

ToPrimitive ( input [ , preferredType ] )

将输入的参数转换成非对象类型(原始值)

  1. 断言:input输入是一个ECMAScript语言的值

  2. 如果输入的类型是对象

    1. 获取对象上toPrimitive方法,如果存在,

      1. 如果preferredType不存在,按default转换
      2. 如果preferredType是“string”,那就按“string”转换
      3. 否则,将断言preferredType成“number“,按“number“转换
      4. 如果经过转换后result不是对象了就返回,否则报错Throw a TypeError exception
  3. 返回input(原始类型)

对象转原始值OrdinaryToPrimitive ( O, hint )

  1. 将O断言成对象类型

  2. 判断要转换的类型hint是string还是number

  3. 如果要转换成string,那么调用顺序是"toString","valueOf"

    1. 如果调用toString返回一个原始值,JavaScript 将这个值转换为字符串,并返回这个字符串结果。
    2. 如果对象没有 toString 方法,或者这个方法并不返回一个原始值,那么 JavaScript 会调用 valueOf 方法。如果存在这个方法,则 JavaScript 调用它。如果返回值是原始值,JavaScript 将这个值转换为字符串,并返回这个字符串的结果
    3. 否则,JavaScript 无法从 toString 或者 valueOf 获得一个原始值,这时它将抛出一个类型错误异常
  4. 如果要转换成number,那么调用顺序是"valueOf","toString"

    1. 同3
  5. 否则,JavaScript 抛出一个类型错误异常

ToBoolean ( argument )

argument Typeresult
Undefinedfalse
Nullfalse
Booleanreturn argument
Numberif +0、-0、NaN return false;
otherwise return true
String空字符串返回false,其他的都是true
Symboltrue
BigIntIf argument is 0ℤ, return false; otherwise return true.
Objecttrue

ToNumber

argument Typeresult
UndefinedNaN
Null+0
Booleantrue: 1; false: 0
NumberReturn argument (no conversion).
String见例子
SymbolTypeError
BigIntTypeError
Object1. Let primValue be ? ToPrimitive(argument, number).
2. Return ? ToNumber(primValue).
console.log(Number()) // +0

console.log(Number(undefined)) // NaN
console.log(Number(null)) // +0

console.log(Number(false)) // +0
console.log(Number(true)) // 1

console.log(Number("123")) // 123
console.log(Number("-123")) // -123
console.log(Number("1.2")) // 1.2
console.log(Number("000123")) // 123
console.log(Number("-000123")) // -123

console.log(Number("0x11")) // 17

console.log(Number("")) // 0
console.log(Number(" ")) // 0

console.log(Number("123 123")) // NaN
console.log(Number("foo")) // NaN
console.log(Number("100a")) // NaN

Number函数会尽可能多的解析数值字符,将它转换成整数或浮点数,忽略所有前导的0,如果有一个字符不是数字,结果都会返回 NaN。除此之外我们还有parseInt 和 parseFloat 进行数值转换。

parseInt 只解析整数,parseFloat 则可以解析整数和浮点数, 尽可能解析更多数值字符,并忽略后面的内容。如果第一个非空格字符是非法的数字直接量,将最终返回 NaN。

ToString

argument Typeresult
Undefined“undefined”
Null“null”
Boolean“true”; “false”
NumberNumber.toString(argument)
StringReturn argument (no conversion).
SymbolTypeError
BigIntBigInt.toString(argument)
Object1. Let primValue be ? ToPrimitive(argument, number).
2. Return ? ToString(primValue).

ToObject

始值通过调用 String()、Number() 或者 Boolean() 构造函数,转换为它们各自的包装对象。

null 和 undefined 属于例外,当将它们用在期望是一个对象的地方都会造成一个类型错误 (TypeError) 异常,而不会执行正常的转换。

JSON.stringify

参考:github.com/mqyqingfeng…

运算符

在js运算中通常某些运算符会发生隐式类型转换,如一元操作符+、二元操作符+、==运算符这些,在运算过程中会发生数据类型转换,得到的值和我们想象的可能不太一样

一元操作符+

当 + 运算符作为一元操作符的时候,查看 ES5规范1.4.6,会调用 ToNumber 处理该值,相当于 Number('1'),最终结果返回数字。

转换步骤见上面ToNumber函数

二元操作符+

  1. 如果操作数是对象,那么对象转为原始值
  2. 如果一个操作数是字符串,那么另一个操作数也转成字符串,进行字符串拼接
  3. 否则两个数都变成数字或NaN进行加法操作

==运算符

执行x == y

  1. 如果x和y是同一类型,执行===严格相等比较

  2. x是null并且y是undefined,返回true

  3. x是undefined并且y是null,返回true

  4. 如果x是Number,y是String,那么比较 x == ToNumber(y)

  5. 如果x是String,y是Number,那么比较 ToNumber(x) = y

  6. 如果x是BigInt,y是String

    1. 将string转换成Bigint,赋值与变量n
    2. n如果是NaN,返回false
    3. 返回x==n的结果
  7. 其中一个是Boolean,那么比较ToNumber(x) = y或x = ToNumber(y)

  8. x是字符串或者数字,y是对象,判断x == ToPrimitive(y)

  9. 返回false

===严格相等比较

  1. 两者类型不同,返回false
  2. 如果x是数字类型或者BigInt,比较x是否等于y
  3. 返回SameValueNonNumeric(x, y)

SameValueNonNumeric(x, y)

  1. x和y都不是Number或BigInt(不然在上述第二步就执行了)

  2. x和y的类型是相同的(不然在上述第一步就执行了)

  3. 如果x是undefined,返回true

  4. 如果x是null,返回true

  5. 如果x是string

    1. 只有x和y是完全相同的代码序列(长度相同、在相同的索引出有相同的代码单元)才返回true,否则返回false
  6. 如果x是boolean

    1. 只有x和y都是true或者false才返回true,否则返回false
  7. 如果x是symbol

    1. 只有x和y有相同的symbol值,才返回true,否则返回false
  8. 只有x和y有相同的对象值,才返回true,否则返回false