Skip to content

Latest commit

 

History

History
199 lines (174 loc) · 5.6 KB

类型.md

File metadata and controls

199 lines (174 loc) · 5.6 KB

类型

type

内置类型

基本类型

  • Boolean
  • String
  • Number
  • Null
  • Undefined
  • Symbol(ES6 新定义)

1、typeof

正常情况下:

typeof 1 // 'number'
typeof '1' // 'string'
typeof undefined // 'undefined'
typeof true // 'boolean'
typeof Symbol() // 'symbol'
typeof b // b 没有声明,但是还会显示 undefined

特殊情况下:

typeof [] // 'object'
typeof {} // 'object'
typeof console.log // 'function'
typeof null // 'object'

PS:为什么会出现这种情况呢?因为在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。

如果我们想获得一个变量的正确类型,可以通过 Object.prototype.toString.call(xx)。这样我们就可以获得类似 [Object Type] 的字符串。

let a = {};
Object.prototype.toString.call(a)
"[object Object]"

let b = '11';
Object.prototype.toString.call(b)
"[object String]"

2、instanceof

用于实例和构造函数的对应。例如判断一个变量是否是数组,使用typeof无法判断,但可以使用[1, 2] instanceof Array来判断。因为,[1, 2]是数组,它的构造函数就是Array。

function instanceof(left, right) {
    // 获得类型的原型
    let prototype = right.prototype
    // 获得对象的原型
    left = left.__proto__
    // 判断对象的类型是否等于类型的原型
    while (true) {
    	if (left === null)
    		return false
    	if (prototype === left)
    		return true
    	left = left.__proto__
    }
}

引用类型

值类型与引用类型

  • Object
    • Function
    • Date
    • Array
    • 等等

1、值类型与引用类型的区别

var obj = {
    a: 1,
    b: [1,2,3]
}
var a = obj.a
var b = obj.b
a = 2
b.push(4)
console.log(obj, a, b)
// a:1
   b:(4) [1, 2, 3, 4]

虽然obj本身是个引用类型的变量(对象),但是内部的a和b一个是值类型一个是引用类型,a的赋值不会改变obj.a,但是b的操作却会反映到obj对象上。

JS 中这种设计的原因是:按值传递的类型,复制一份存入栈内存,这类类型一般不占用太多内存,而且按值传递保证了其访问速度。按共享传递的类型,是复制其引用,而不是整个复制其值(C 语言中的指针),保证过大的对象等不会因为不停复制内容而造成内存的浪费。

类型转换

转 Boolean

在条件判断时,除了 undefined, null, false, NaN, '', 0, -0,其他所有值都转为 true,包括所有对象

对象转基本类型

对象在转换基本类型时,首先会检查有无设置 Symbol.toPrimitive 该方法优先级最高,然后调用 valueOf,然后调用 toString。三个方法都可以重写。

let a = {
  valueOf() {
    return 0;
  },
  toString() {
    return '1';
  },
  [Symbol.toPrimitive]() {
    return 2;
  }
}
1 + a // => 3
'1' + a // => '12'

四则运算符

  • 加法运算:其中一方是字符串类型,就会把另一个也转为字符串类型
  • 非加法运算:只要其中一方是数字,那么另一方就转为数字
  • 加法运算会触发三种类型转换:将值转换为原始值,转换为数字,转换为字符串。
1 + '1' // '11'
2 * '2' // 4

[1, 2] + [2, 1] // '1,22,1'
// [1, 2].toString() -> '1,2'
// [2, 1].toString() -> '2,1'
// '1,2' + '2,1' = '1,22,1'
'a' + + 'b' // -> "aNaN"
// 因为 + 'b' -> NaN
// 你也许在一些代码中看到过 + '1' -> 1

==操作符

alt 题目:[] == ![] // -> true

//!的优先级较==高,先运算==右侧的操作数:[]是对象,会转换成true,然后再转成false(加!的一定是转换成boolean)

// [] 转成 true,然后取反变成 false
[] == false
// 根据第 8 条得出
[] == ToNumber(false)
[] == 0
// 根据第 10 条得出
ToPrimitive([]) == 0
// [].toString() -> ''
'' == 0
// 根据第 6 条得出
0 == 0 // -> true

比较运算符

  1. 如果是对象,就通过 toPrimitive 转换对象
  2. 如果是字符串,就通过 unicode 字符索引来比较

相等和全等

相等和不相等——先转换再比较
全等和不全等——仅比较而不转换

相等(==)和不相等(!=)

类型转换:这两个操作符都会先转换操作数(强制转型),然后再比较它们的相等性。

规则:

1. 一个是布尔,比较之前先转换成数值——false转0,true转1
2. 一个是字符串,一个是数值 ,比较之前先将字符串转成数值
3. 一个是对象,另一个不是,则调用对象的valueof方法,用得到的基本类型值按照前面的规则进行比较

比较时遵循:
1. null和undefined相等
2. 一个是NaN,相等操作符则返回false。不相等操作符则返回true。
3. 两个都是对象,则比较是否是同一个对象。如果两个操作数指向同一个对象,
则相等操作符返回true。否则返回false
null==undefined//true
"NaN"==NaN//false
5==NaN//false
NaN==NaN//false
NaN!=NaN//true
false==0//true
true==1//true
true==2//true
undefined==0//false
null==0//false
"5"==5//true

全等(===)和不全等(!==)

除了在比较之前不转换操作数外,全等和不全等与相等和不相等没有什么区别

"55"===55//false
null===undefined//false