JavaScript类型问题
JavaScript 类型的问题其实是个挺折磨人的话题, 不然也不会有 TypeScript 出现了。此篇博文主要记录与此相关的一些问题。有兴趣研究的同学可以去阅读 lodash 的源代码,学习在这种成熟的JS库中是如何处理类型问题以及如何进行类型判断的。
JavaScript内置类型
* null
* undefined
* boolean
* number
* string
* object
* symbol (ES6中新增类型)
除了object之外,其他统称为基本数据类型。object类型则包括Object 、Array 、Function 、Date等,我们一般也把它们称为引用数据类型。
基本数据类型的值存放在栈(Stack)中,而引用数据类型的值存放在堆(Heap)中,栈中只存放对它们的“引用”
JavaScript常见的一些类型问题
1、== 和 ===问题
相等(==)
比较操作符会为两个不同类型的操作数转换类型,然后进行严格比较。当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。
1
2
3
41 == 1 // true
"1" == 1 // true
1 == '1' // true
0 == false // true
严格相等(===)
一致运算符不会进行类型转换,仅当操作数严格相等时返回true
1
2
3
4
53 === 3 // true
3 === '3' // false
var object1 = {"value":"key"}, object2={"value":"key"};
object1 === object2 //false
undefined == null // true可以很明显的看出,== 和===的区别就在于在判断的时候是否进行了自动的**类型转换**。需要注意的是ECMAScript认为undefined是从null派生出来的,所以把它们定义为相等的 。
2、如何判断JavaScript中变量的类型
typeof
主要用于判断数据是不是基本数据类型:String、Number、Object、Null、Undefined,但是无法判断出function(有些浏览器会出错,V8中能正常判断 )、array、regExp
1
2
3
4
5
6
7
8
9console.log(typeof '');//string
console.log(typeof []);//object
console.log(typeof {});//object
console.log(typeof 1);//number
console.log(typeof null);//object
console.log(typeof undefined);//undefined
console.log(typeof true);//boolean
console.log(typeof function(){});//function
console.log(typeof /\d/);//objectinstanceof
instanceof 左操作数是一个类,右操作数是标识对象的类。如果左侧的对象是右侧类的实例,则返回true.而js中对象的类是通过初始化它们的构造函数来定义的。即instanceof的右操作数应当是一个函数。所有的对象都是object的实例。如果左操作数不是对象,则返回false,如果右操作数不是函数,则抛出typeError。
1
2
3
4
5new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true
'foo' instanceof String; // false
'foo' instanceof Object; // falseObject.prototype.toString.call()
这是对象的一个原生原型扩展函数,用来精确的区分数据类型
1
2
3
4
5
6
7const toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]上述的3种类型判断方式都有各有利弊,typeof验证**基本数据类型**(除了null哦) 一般不会有什么问题,但是验证引用数据类型,则会出现各种谬误。instanceof用来验证一个对象是否是一个类的实例,但是由于JavaScript中所有引用数据类型都是继承自Object,所以没法判断对象的准确类型。Object.prototype.toString.call()虽然可以精确判断数据类型,但是在面对自定义的类型时也存在风险。(想一下,如果我重写了Array的toString方法)
3、基本数据类型以及引用数据类型的问题(值传递与引用传递)
> js 中什么类型是引用传递, 什么类型是值传递? 如何将值类型的变量以引用的方式传递?
简单点说, 对象是引用传递, 基础类型是值传递, 通过将基础类型包装 (boxing) 可以以引用的方式传递 。例如 a = new Number(1)
这时候a 就可以使用引用的方式传递了
这地方有一个有意思的小问题。用更严谨的技术说法,在JavaScript中没有所谓的引用传递而是传递引用,也叫作call-by sharing 。想要了解的同学可以看看Stack Overflow上的这个讨论Is JavaScript a pass-by-reference or pass-by-value language?
调用函数传参时,函数接受对象实参引用的副本(既不是按值传递的对象副本,也不是按引用传递的隐式引用)。 它和按引用传递的不同在于:在共享传递中对函数形参的赋值,不会影响实参的值。 然而,虽然引用是副本,引用的对象是相同的。它们共享相同的对象,所以修改形参对象的属性值,也会影响到实参的属性值。
换句话来说
值传递:传内存拷贝
引用传递:传内存指针
共享传递(call-by sharing):传内存指针的拷贝
4、JavaScript中值为false的值
- null
- undefined
- “” (空字符串)
- NaN
- 0
- false