一、类型与包装对象

1. 类型

原始类型:

  • number
  • string
  • boolean
  • null
  • undefined
  • Symbol

对象类型:

  • Object
  • Array
  • Function

原始类型(基本类型)和对象类型(引用类型)的区别:

  • 原始类型不能修改值,对象类型可以。
    分析:原始类型存储在栈内存中,对象类型存储在堆内存中。原始类型的修改都是重新赋值。
    即,声明一个原始类型,var a = 2;那么会在栈内存中开辟一块内存用于存储原始类型a,当重新赋值a = 234的时候,会重新开辟一块栈内存用于存储重新赋值的原始类型a2则被垃圾回收机制回收。
    至于对象类型,栈内存中存的是对象数据在堆内存中的首地址,也就是该数据的引用。在访问变量的时候就会去堆内存中找引用对象的值,修改的时候也是修改堆内存中的值。

clipboard.png

  • 原始类型没有属性和方法,对象类型可以有

null和undefined的区别:

  • undefined表示一个未被赋值的栈内存的空间,null表示栈空间的引用没有指向一个地址
  • 进行显示类型转换时,null为0,undefined为NaN
  • typeof(null) === 'object'
    typeof(undefined) ==='undefined'

2. 包装对象

包装对象-by阮一峰/W3cschool(2019.1.4)
JS语言:“一切皆对象”,数组和函数本质上是对象,三种原始数据类型的值(数值、字符串、布尔值
)在一定条件下、也会自动转为对象、这就是原始类型的“包装对象”。
包装对象:即,与数值、字符串、布尔值相对应的Number、String、Boolean三个原生对象。三个原生对象可以把原始类型的值变成(包装成)对象。

var num = new Number(123);
var str = new String('abc');
var bool = new Boolean(true);

例如:

var str = 'test';//通过字符串字面量定义的字符串值不是对象
str.length  //4
str.slice(0,1) //'t'

var a = 7;
a.toString() //'7'

str是原始类型string的变量,进行属性和调用方法的操作时,js会通过new String()构建一个包装对象(临时的),这个包装对象再进行属性和方法的访问,访问结束后,js会销毁该包装对象,所以只能读不能改。null和undefined没有构造函数,所以也没有包装对象,如果访问其属性和方法将会跑出异常。
补充:toString()方法是Number对象的方法,把数字转换成字符串。

3. 类型转换

JS是弱类型,无论什么类型都是通过var来声明。
https://www.jb51.net/article/...
一定为false的值:

0或+0、-0,NaN //数值
"" //空字符串值
false //false布尔值
undefined
null

if (a && b)的正确理解方式是:a && b进行表达式求值后,然后再转换为Boolean类型。
☆ 显示类型转换(强制转换)
即,显示调用String();Number();Boolean()函数进行类型转换。

clipboard.png

var a = [9,8]//数组
    String(a)//'9,8'

var a = 123
String(a) // '123'
Boolean(a) // true
var b = '123a'
Number(b) // NaN
Boolean(b) // true

//引用类型显示转换为原始类型
var a = ['9']
Number(a) // 9
String(a) // '9'
var b = {
c: 'this is a time',
toString: function(){
return 5
}
}
Number(b) // 5
String(b) // '5'

☆ 隐式转换(自动转换,用的比较多)原始类型的类型转换,引用类型的转换。
通过运算符进行转换,例如:== + -
注意:===运算符,是类型和数值都一样,才能返回true
以==为例:
首先,null和undefined==其他类型都为false。

clipboard.png

null == undefined只能跟自己和对方==返回true,其他情况是false;
可以进行强制类型转换:

var a = null
String(a)
a==null //强制类型转换,并不会影响a本身的值,只是在运算的时候不同

clipboard.png

然后,原始类型之间的转换,都是以构造函数进行转换,即将==两边的值都转换成Number再进行比较
引用类型转换为原始类型过程:
1.先调用valueOf()方法,如果返回原始类型,则结束,否则执行下一步
2.接着调用toString()方法,得到初步原始类型(初步原始类型一定是一个非空字符串)
3.将得到的初步原始类型转换为目标原始类型

clipboard.png

所有引⽤用类型的最顶层的proto对象(可以理解为基类),都为Object的prototype,其必包含toString方法,该方法返回数据类型字符串,转换为boolean为true,所以所有的对象都为true。

clipboard.png

var a = {}, b = []
if(a) {}
if(b) {} // 不能通过这个⽅方式判定对象和数组为空,因为空数组或者空对象转换成boolean值,都为true

原始类型的转换:

“123” == false //false
“123” == true  //false

分析:true转换为1了,false转换成了0;“123”转换成了123.
==符号会把两边都会类型转换成Number,再进行对比

var obj = {a:"123"}
console.dir()
obj.valueOf

☆ 拓展:
object类型具有valueOf()和toString()方法。valueOf()返回对象的字符串、数值或布尔值表示,通常与toString()返回的值相同。toString()返回对象的字符串表示。但是!!!!实际上:
拿数组为例,toString方法返回的是由数组中每个值的字符串形式拼接而成的一个由逗号分隔的字符串;valueOf方法返回的还是一个数组。

clipboard.pngclipboard.png

☆ ==与===
== 判断相等时,如果两边类型不同时,会进行类型转换
===(绝对等于号) 判断相等时,不进行类型转换,类型不同,其值⼀定不绝对等于
当两边都为引用类型时,== 和 === 都是判断两边是否指向同⼀个数据,是则为true,否则为
false

[] == [] // false
{} == {} // false
var a = b = {}
a == b // true
a === b // true

☆经典面试题:设计一个函数,让a既等于1又等于2又等于3。
考的是类型转换,原始类型肯定是不可以的。

题目:a为何值时,下面表达式为true
if(a == 1 && a == 2 && a == 3){
//
}
答案:
var a = {
b: 0,
toString: function(){
return ++this.b
}
}      

原理:

clipboard.png

4.类型判断

1)typeof运算符

typeof 1 // ‘number’
typeof NaN // 'number'
typeof {} // 'Object'
typeof null // 'Object'
typeof undefined // 'undefined'
var a = function(){}
typeof a // 'function'

缺点:typeof只能判断原始类型和函数,不能判断引用类型和null,它们都返回'object'.
2)instanceof
使用方法:对象 instanceof 构造方法

[] instanceof Array // true
[] instanceof Object // true
var b = {}
b instanceof Object // true
var a = function(){}
a instanceof Function // true

原理:instanceof运算符检测左边对象的原型链上是否有右边构造函数的prototype对象。
缺点:
只能用来判断对象;
不能跨iframe使用,因为不同iframe其window不同.
3)constructor

[].constructor === Array // true
'123'.constructor === String // true
function Fn(){
}
var f = new Fn()
f.constructor === Fn // true

原理:构造函数的prototype对象指向构造函数本身,创建新对象后,新对象继承prototype对象,因此新对象的constructor指向了构造函数。
缺点:不能用来判断null、undefined;
prototype对象可被重写,constructor会丢失。
4)toString——最通用的方法
toString是Object的原型⽅方法,默认返回当前对象的类型,对所有情况都可以判断。

Object.prototype.toString.call('1234') // ['Object String']
Object.prototype.toString.call([]) // ['Object Array']
Object.prototype.toString.call({}) // ['Object Object']
Object.prototype.toString.call(null) // ['Object Null']
Object.prototype.toString.call(undefined) // ['Object Undefined']

5)其他判断方法

Array.isArray([]) // true
isNaN(NaN) // true 


lumiere
28 声望3 粉丝

越努力,