原始类型
-
null
-
undefined
-
boolean
-
number
-
string
-
symbol
注意
-
原始类型存储的都是值,是没有函数可以调用的,但实际上除
null
和undefined
外,其他类型使用函数时会被转成对应的对象类型,从而可以使用其对象类型原型链上的方法。 -
虽然
typeof null
输出object
,但它不是对象类型,只是一个历史悠久的bug,在JS的最初版本中使用的是32位系统,为了性能考虑使用低位存储变量的类型信息,000开头代表是对象,然而null
表示为全零,所以将它错误的判断为object
。
对象类型
在js中,除了原始类型,其他的都是对象类型了。对象类型和原始类型不同的是,原始类型存储的是值,对象类型存储的是地址(指针)。
const a = [] //常量a来说,假设内存地址(指针)为#001,那么在地址#001的位置存放了值[],常量a存放了地址(指针)#001
const b = a //当我们将变量赋值给另外一个变量时,复制的是原本变量的地址(指针),也就是说当前变量b存放的地址(指针)也是#001
b.push(1) //当我们进行数据修改的时候,就会修改存放在地址(指针)#001上的值,也就导致了两个变量的值都发生了改变。
类型转换
在 JS 中类型转换只有三种情况,分别是:
-
转换为布尔值
-
转换为数字
-
转换为字符串
注意:图中有一个错误,Boolean转字符串这行仅值true转字符串的例子,不是说 Boolean、函数、Symblo转字符串都是true
转Boolean
在条件判断时,除了undefined
,null
,false
,NaN
,'',0
,-0
,其他所有值都转为true
,包括所有对象。
对象转原始类型
对象在转换类型的时候,会调用内置的[[ToPrimitive]]
函数,对于该函数来说,算法逻辑一般来说如下:
-
如果已经是原始类型了,就不需要转换了(因为可以重写
Symbol.toPrimitive
,所有这种情况是存在的) -
如果需要转换为字符串类型,则直接调用
toString
方法,转换为基础类型的话就返回转换的值。 -
如果不是字符串类型,则先调用
valueOf
方法,结果不是基础类型的话再调用toString
方法 -
如果以上处理后,都没有返回原始类型,就会报错
本人小疑惑:有哪些对象调用
valueof
方法后会转换为基础类型? (发现一个,Date对象)
四则运算符
-
加法
-
运算中其中一方为字符串,那么就会把另一方也转换为字符串
-
如果一方不是字符串或者数字,那么会将它转换为数字或者字符串(具体转换参照对象转原始类型)
1 + '1' // '11' true + true // 2 4 + [1,2,3] // "41,2,3"
-
-
其他运算符
- 只要其中一方是数字,那么另一方就会被转为数字
4 * '3' // 12 4 * [] // 0 4 * [1, 2] // NaN
比较运算符
1.如果是对象,则转换为原始类型再比较值
2.如果是字符串,就通过unicode
字符索引来比较(我猜测是逐个字符进行对比大小,希望知道的朋友不吝赐教)
'6'.charCodeAt() //54
'啊'.charCodeAt() //21834
'6' < '啊' //true
'6' > '5啊' //true
this
三种最常见的场景:
//1
function foo() {
console.log(this.a)
}
var a = 1
foo()
//2
const obj = {
a: 2,
foo: foo
}
obj.foo()
//3
const c = new foo()
-
对于直接调用
foo
来说,不管foo
函数被放在了什么地方,this
一定是window
-
对于
obj.foo()
来说,我们只需要记住,谁调用了函数,谁就是this
,所以在这个场景下foo
函数中的this
就是obj
对象 -
对于
new
的方式来说,this
被永远绑定在了c
上面,不会被任何方式改变this
箭头函数
function a() {
return () => {
return () => {
console.log(this)
}
}
}
console.log(a()()())
首先箭头函数其实是没有this
的,箭头函数中的this
只取决包裹箭头函数的第一个普通函数的this
。在这个例子中,因为包裹箭头函数的第一个普通函数是a
,所以此时的this
是window
。
bind
let a = {}
let fn = function () { console.log(this) }
fn.bind().bind(a)() // => ?
不管我们给函数bind
几次,fn
中的this
永远由第一次bind
决定,所以结果永远是window
。
// fn.bind().bind(a) 等于
let fn2 = function fn1() {
return function() {
return fn.apply()
}.apply(a)
}
fn2()
优先级
多个规则同时出现时,这时候不同的规则之间会根据优先级最高的来决定this
最终指向哪里。
首先,new
的方式优先级最高,接下来是bind
这些函数,然后是obj.foo()
这种调用方式,最后是foo
这种调用方式,同时,箭头函数的this
一旦被绑定,就不会再被任何方式所改变。