JavaScript - 数据小知识

1、JavaScript中的数据类型

↬ JavaScript中的数据一共有八种:NumberStringBooleanUndefinedNullObjectSymoblBigInt

↬ 主要分为两种,分别是:
原始数据类型引用数据类型


1.1 原始数据类型

↬ 原始数据类型有:
NumberStringBooleanUndefinedNullSymoblBigInt

其中 Symobl、BigInt是ES6新增的数据类型;
 
Symobl:通过Symobl创建的数据类型是独一无二的并不可被改变,可以用于解决可能出现的全局变量冲突以及对象属性不唯一的问题;
 
BigInt:表示一种数字类型的数据,可以表示任意精度格式的整数,可以安全的存储与操作即使超出了Number所能表示的范围的大整数;


1.2 引用数据类型

↬ 引用数据类型只有Object;

Object类型是一个大类,ArrayFunctionDate等内置对象都是Object类型的子类;


1.3 原始数据类型与引用数据类型的区别

其主要区别在于他们的存储位置的不同:
引用数据类型:数据存储在内存中,指向数据的指针,存放在栈内存中,当访问引用数据的时候,先是在栈内存中检索指针,然后通过指针找到数据;
原始数据类型:数据直接存储在内存中;
 
堆内存与栈内存的区别

➢ 堆与栈的概念存在于操作系统内存与数据结构中;

数据结构中的堆与栈:在数据结构中,栈中的数据存取方式是先进后出,而堆是一个优先队列,按照优先级来进行排序的,优先级可以按照大小来规定;
 
操作系统内存中的堆与栈:在操作系统中,内存被分为堆区与栈区。
➲ 栈区内存由编译器自动分配与释放,用于存放函数的参数值,局部变量的值等,其操作方式类似于数据结构中的栈。
➲堆区内存一般由开发者分配与释放,若开发者不对堆区内存进行释放,那么程序结束时,可能会由垃圾回收机制进行回收。


2、检测数据类型的方法

2.1 typeof

在JavaScript中,typeof是一个运算符,通过该方法可以检测出数据的类型。

	console.log(typeof 1)               // number
	console.log(typeof '1')             // string
	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 [])              // object

由上方可以看出,通过typeof检测引用数据类型的时候,除Function外,检测出的类型都是Object类型,甚至连null检测出来的都是Object类型;
 
原因是因为,typeof 操作符是按照数据在计算机底层存储的二进制结果进行检测的。而null的二进制为:000000,所有的Object类型的数据在计算机底层存储的二进制都是000开头的,所以typeof无法很好的识别出Object类型与null数据类型;


2.2 instanceof

运行原理:检测实例对象是否是该构造函数的实例对象,主要通过查询被检测对象的原型链上,能否找到与目标对象相同的原型;

	console.log(1 instanceof Number)                // false
	console.log('1' instanceof String)              // false
	console.log(true instanceof Boolean)            // false


	console.log(function(){} instanceof Function)   // true
	console.log({} instanceof Object)               // true
	console.log([] instanceof Array)                // true

通过上方可以看出,instanceof只能判断引用类型,不能判断基本数据类型,但是我们通过构造函数的方式去创建一个Number类型的值,就可以通过instanceof进行检测。

	const a = new Number(1)
	const b = Number(2)
	const c = 3

	console.log(a, a instanceof Number)    // Number{1} true
	console.log(b, b instanceof Number)    // 2 false
	console.log(c, c instanceof Number)    // 3 false

手写 instanceof 方法

    function myInstanceof(instance, type) {
        let proto = Object.getPrototypeOf(instance) // 获取实例对象的原型
        let prototype = type.prototype // 获取构造函数的prototype对象

        while (true) {
            // 实例对象原型为null时返回 false
            if (!proto) return false;

            // 当查找到的原型与目标对象的prototype对象全等时,返回true
            if (proto === prototype) return true;

            // 沿着原型链向上查找,直到查找至Null为止
            proto = Object.getPrototypeOf(proto);
        }
    }

    console.log(myInstanceof(1, Number))	// true
    console.log(myInstanceof('1', String))	// true
    console.log(myInstanceof(true, Boolean))	// true
    console.log(myInstanceof({}, Object))		// true
    console.log(myInstanceof([], Array))		// true
    console.log(myInstanceof(function () {}, Function))	//true

2.3 constructor

constructor属性,不仅可以让实例对象访问其构造函数,还可以做数据类型的判断;

    console.log((1).constructor === Number);    // true
    console.log(('1').constructor === String);  // true
    console.log((true).constructor === Boolean);    // true

    console.log(({}).constructor === Object);   // true
    console.log((function () {}).constructor === Function); // true
    console.log(([]).constructor === Array);    // true

2.4 Object.prototype.toString.call()

toString是Object原型上的方法,Array、function等类型作为Object
的实例,都重写了toString方法。不同的对象类型调用toString方法时,调用的都是重写后的方法(function类型返回内容为函数体的字符串,Array类型返回内容为元素组成的字符串等),而不会去调用Object上原型toString方法(返回对象的具体数据类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,想要得到对象的具体类型,应该调用原型上的toString方法。

    let obj = {
        name:'link',
        age:18
    }

    function fun() {
        return 1
    }

    let arr = [1, 2, 3]

    console.log(obj.toString())
    console.log(arr.toString())
    console.log(fun.toString())

在这里插入图片描述

    let obj = {
        name: 'link',
        age: 18
    }

    function fun() {
        return 1
    }
    
    let arr = [1, 2, 3]

    console.log(Object.prototype.toString.call(1))
    console.log(Object.prototype.toString.call('1'))
    console.log(Object.prototype.toString.call(true))
    console.log(Object.prototype.toString.call(undefined))
    console.log(Object.prototype.toString.call(null))

    console.log(Object.prototype.toString.call(obj))
    console.log(Object.prototype.toString.call(fun))
    console.log(Object.prototype.toString.call(arr))

在这里插入图片描述


3、类型转换

在JavaScript中数据类型转换分为两种,分别是显示类型转换、隐式类型转换;
 
显示类型转换:强制类型转换,由开发人者通过内置方法转换数据类型,如:Number(‘123’);
 
隐式类型装换:当对不同类型的值使用运算符的时候,值会在类型之间自动的切换;


3.1 == 操作符号的类型转换规则

对于 == 操作符来说,如果对比的双方的类型不同,就会进行类型的转换,其判断流程如下:

  1. 首先会判断两者类型是否相同;
  2. 类型不同就进行转换;
  3. 判断是否在对比 nullundefined,如果是的话,就返回true
  4. 判断两者类型是否为 StringNumber,是的话,会将String类型转换为Number类型
  5. 判断其中一方是否为Boolean类型,如果是就会把Boolean转换为number类型进行比较
  6. 判断其中一方是否为Object且另一方为StringNumber 或者 Symobl,是的话,就会把Object转为原始类型进行判断。
    流程图如下

在这里插入图片描述

// 操作符两边的值都尽量转换成Number

3 == true // false, 3 转为number为3,true转为number为1 
'0' == false //true, '0'转为number为0,false转为number为0 
'0' == 0 // '0'转为number为0

3.2 其他类型转String的规则

  • NullUndefined 类型 ,null 转换为 "null"undefined 转换为 "undefined"
  • Boolean 类型,true 转换为 "true"false 转换为 "false"
  • Number 类型的值直接转换,不过那些极小和极大的数字会使用指数形式。
  • Symbol 类型的值直接转换,但是只允许显式强制类型转换,使用隐式强制类型转换会产生错误。
  • 对普通对象来说,除非自行定义 toString() 方法,否则会调用 toString()(Object.prototype.toString())来返回内部属性 [[Class]] 的值,如"[object Object]"。如果对象有自己的 toString() 方法,字符串化时就会调用该方法并使用其返回值。

3.3 其他类型转Number的规则

  • Undefined 类型的值转换为 NaN
  • Null 类型的值转换为 0
  • Boolean 类型的值,true 转换为 1false 转换为 0
  • String 类型的值转换如同使用 Number() 函数进行转换,如果包含非数字值则转换为 NaN,空字符串为 0
  • Symbol 类型的值不能转换为数字,会报错。
  • 对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则再遵循以上规则将其强制转换为数字。

为了将值转换为相应的基本类型值,抽象操作 ToPrimitive 会首先(通过内部操作 DefaultValue)检查该值是否有valueOf()方法。如果有并且返回基本类型值,就使用该值进行强制类型转换。如果没有就使用 toString() 的返回值(如果存在)来进行强制类型转换。

【注意】如果 valueOf()toString() 均不返回基本类型值,会产生 TypeError 错误。


3.4 其他类型转Boolean的规则

以下这些是假值:

  • undefined
  • null
  • false
  • +0-0NaN
  • ""

假值的布尔强制类型转换结果为 false。从逻辑上说,假值列表以外的都应该是真值。


3.5 补充

首先要介绍ToPrimitive方法,这是 JavaScript 中每个值隐含的自带的方法,用来将值 (无论是基本类型值还是对象)转换为基本类型值。如果值为基本类型,则直接返回值本身;如果值为对象,其看起来大概是这样:

/** 
* @obj 需要转换的对象 
* @type 期望的结果类型 
*/ 
ToPrimitive(obj,type)

type的值为number或者string

(1)当type为number时规则如下

  • 调用objvalueOf方法,如果为原始值,则返回,否则下一步;
  • 调用objtoString方法,后续同上;
  • 抛出TypeError 异常。

(2)当type为string时规则如下

  • 调用objtoString方法,如果为原始值,则返回,否则下一步;
  • 调用objvalueOf方法,后续同上;
  • 抛出TypeError 异常。

可以看出两者的主要区别在于调用toStringvalueOf的先后顺序。默认情况下:

  • 如果对象为 Date 对象,则 type 默认为 string
  • 其他情况下,type 默认为 number

总结上面的规则,对于 Date 以外的对象,转换为基本类型的大概规则可以概括为一个函数:

var objToNumber = value => Number(value.valueOf().toString()) 
objToNumber([]) === 0 
objToNumber({}) === NaN

而 JavaScript 中的隐式类型转换主要发生在+、-、*、/以及==、>、<这些运算符之间。而这些运算符只能操作基本类型值,所以在进行这些运算前的第一步就是将两边的值用ToPrimitive转换成基本类型,再进行操作。

3.5.1 + - * / 操作符

+ 操作符的两边有至少一个 string类型变量时,两边的变量都会被隐式转换为字符串;其他情况下两边的变量都会被转换为数字。

1 + '23' // '123' 
1 + false // 1 
1 + Symbol() // Uncaught TypeError: Cannot convert a Symbol value to a number 
'1' + false // '1false' 
false + true // 1

-*/ 操作符转换出来的也是数字

1 * '23' // 23 
1 * false // 0 
4 / 2 // 2
'2' - 1 // 1 number

3.5.2 < > 比较符

如果两边都是字符串,则比较字母表顺序:

'ca' < 'bd' // false
'a' < 'b' // true

其他情况下,转换为数字在进行比较:

'12' < 13	// true
false > -1	// true

以上说的是基本类型的隐式转换,而对象会被ToPrimitive转换为基本类型再进行转换:

var a = {}

a > 2	// false

// 对比过程如下:
a.valueOf() // {}, 上面提到过,ToPrimitive默认type为Number类型,所以先valuOf,结果还是一个对象,进行下一步;
a.toString() // "[object object]", 现在是一个字符串了;
Number(a.toString()) // NaN,根据上面 ‘<’ 和 '>' 的规则,需要转换为Number
NaN > 2 // false, 得出结果

再举一个小栗子:

var a = {name:'Jack'} 
var b = {age: 18} 
a + b // "[object Object][object Object]"

// 运算过程如下:
a.valueOf() // {},上面提到过,ToPrimitive默认type为number,所以先valueOf,结果还是个对象,下一步 
a.toString() // "[object Object]" b.valueOf() // 同理 
b.toString() // "[object Object]" 
a + b // "[object Object][object Object]"


相关文章

……


在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一只 小网虫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值