数据类型以及判断
数据类型
- 基本类型
String
Number
Boolean
null
undefined
Es6 新增 Symbol
- 引用类型
Array
Function
Object
Date
判断
typeof // 返回字符串v,在null、array、object以及函数的实例(new + 函数)时,它返回的都是object。其余可以使用,缺点通常用于基本类型
instanceof // 用于检测构造函数的 `prototype` 属性是否出现在某个实例对象的[原型链]上,返回Boolean,缺点只能用于引用类型
=== // 判断undefined null
Object.prototype.toString.call() // 最准确,但是用法繁琐了点
== 隐式转换以及类型转换
转换为数字
- 通常爱用 '6' * 1
Number()可以把任意值转换成数字,如果要转换的目标对象(一般是字符串)中有不是数字的值,则会返回NaN。
Number('1') // 1
Number(true) // 1
Number('123s') // NaN
Number({}) //NaN
parseInt(string, radix)
解析一个字符串并返回指定基数的十进制整数,radix 是 2-36 之间的整数,表示被解析字符串的基数。
parseInt('2') //2
parseInt('2',10) // 2
parseInt('2',2) // 二进制(01)所以返回 NaN
parseInt('a123') // NaN 如果第一个字符不是数字或者符号就返回NaN
parseInt('123a') // 123
parseFloat(string)
解析一个参数并返回一个浮点数。
parseFloat('123a') //123
parseFloat('123a.01') //123
parseFloat('123.01') //123.01
parseFloat('123.01.1') //123.01
toString()
将目标对象转换为字符串。
注意:null,undefined 不能调用。
Number(123).toString() //'123'
[].toString() //''
true.toString() //'true'
() => {}.toString // '() => {}'
String()
String() 的作用比较强大,它可以将任何传入的值都转为字符串。
String(123) //'123'
String(true) //'true'
String([]) //''
String(null) //'null'
String(undefined) //'undefined'
String({}) //'[object Object]'
String([1, undefined, 3]) // '1,,3' String({}) // '[object Objecr]'
转换为布尔值
Boolean()
Boolean() 方法会将以下值转换为 false:
- 0
- ""
- null
- undefined
- NaN
其余的所有值都会被转换为 true。
ToPrimitive指对象类型类型(如:对象、数组)转换为原始类型的操作。
- 当对象类型需要被转为原始类型时,它会先查找对象的
valueOf方法,如果valueOf方法返回原始类型的值,则ToPrimitive的结果就是这个值 - 如果
valueOf不存在或者valueOf方法返回的不是原始类型的值,就会尝试调用对象的toString方法,也就是会遵循对象的ToString规则,然后使用toString的返回值作为ToPrimitive的结果。 - 如果
valueOf和toString都没有返回原始类型的值,则会抛出异常。
Number([]) // 0
Number(['10']) //10
const obj1 = {
valueOf () {
return 100
},
toString () {
return 101
}
}
Number(obj1) // 100
const obj2 = {
toString () {
return 102
}
}
Number(obj2) // 102
const obj3 = {
toString () {
return {}
}
}
Number(obj3) // TypeError
2. 宽松相等(==)比较时的隐式转换规则
宽松相等(==)和严格相等(===)的区别在于宽松相等会在比较中进行隐式转换。现在我们来看看不同情况下的转换规则。
2.1 布尔类型和其他类型的相等比较
- 只要
布尔类型参与比较,该布尔类型的值首先会被转换为数字类型 - 根据
布尔类型的ToNumber规则,true转为1,false转为0
false == 0 // true
true == 1 // true
true == 2 // false
之前有的人可能觉得数字
2是一个真值,所以true == 2应该为真,现在明白了,布尔类型true参与相等比较会先转为数字1,相当于1 == 2,结果当然是false
我们平时在使用if判断时,一般都是这样写
const x = 10
if (x) {
console.log(x)
}
这里if(x)的x会在这里被转换为布尔类型,所以代码可以正常执行。但是如果写成这样:
const x = 10
if (x == true) {
console.log(x)
}
代码不会按照预期执行,因为x == true相当于10 == 1
2.2 数字类型和字符串类型的相等比较
- 当
数字类型和字符串类型做相等比较时,字符串类型会被转换为数字类型 - 根据字符串的
ToNumber规则,如果是纯数字形式的字符串,则转为对应的数字,空字符转为0, 否则一律按转换失败处理,转为NaN
0 == '' // true
1 == '1' // true
1e21 == '1e21' // true
Infinity == 'Infinity' // true
true == '1' // true
false == '0' // true
false == '' // true
上面比较的结果和你预期的一致吗? 根据规则,字符串转为数字,布尔型也转为数字,所以结果就显而易见了。
这里就不讨论
NaN了,因为NaN和任何值都不相等,包括它自己。
null、undefined和其他类型的比较
null和undefined宽松相等的结果为true,这一点大家都知道
其次,null和undefined都是假值,那么
null == false // false
undefined == false // false
复制代码
webpack相关
-地址
更新 原型和原型链
又捋了一下,仅做笔记
-
先下一个定义 proto [[Prototype]] 隐式原型这些名词是同一个东西
-
显式原型 prototype是同一个东西
-
任何构造函数prototype上的_proto_都指向Object的prototype ,除了Object自身外,因为Object自己prototype上的_proto_指向null,null类似于一个跳出条件,避免造成死循环
-
任何构造函数的constructor都指向Function,等价于任何构造函数的_proto_都指向与Function的prototype,包括Function自身 (Function.constructor === Function Object.proto === Function.prototype)
-
下图摘录只掘金的大佬,感谢
手写new
function P(name, age) {
this.name = name
this.age = age
// return [1]
}
let a = new P('老斋', '38') // 常规操作
// 手写操作
function handleNew(o, ...arg) {
//创建一个空对象 将对象的隐式原型和构造函数的显式原型接起来
let obj = {}
obj.__proto__ = o.protoType;
// 等价于 let obj = Object.create(o.prototype)
// 改变构造函数的this指向,并且传参
let result = o.apply(obj, arg);
// 加一下判断是因为,new实例化函数,如果返回值是引用类型,则会返回引用类型的值,如果是普通类型,则忽略return
// 例如当前P没有返回值(返回值是普通类型undefined)则控制台上 P {name: '老斋', age: '38'},如果有返回值return [1], 则控制台上 [1]
// 为满足以上条件。如果不加判断,要么直接把返回值抛出去,要么直接把obj这个对象抛出去,都是不合理的。
return result instanceof Object ? result : obj
}
let b = handleNew(P, '唠嗑', 51)
console.log(a);
console.log(b);
Event Loop
浏览器内核(渲染进程)
从前文我们得知,进程和线程是一对多的关系,也就是说一个进程包含了多条线程。
而对于渲染进程来说,它当然也是多线程的了,接下来我们来看一下渲染进程包含哪些线程。
-
GUI渲染线程- 负责渲染页面,布局和绘制
- 页面需要重绘和回流时,该线程就会执行
- 与js引擎线程互斥,防止渲染结果不可预期
-
JS引擎线程- 负责处理解析和执行javascript脚本程序
- 只有一个JS引擎线程(单线程)
- 与GUI渲染线程互斥,防止渲染结果不可预期
-
事件触发线程- 用来控制事件循环(鼠标点击、setTimeout、ajax等)
- 当事件满足触发条件时,将事件放入到JS引擎所在的执行队列中
-
定时触发器线程- setInterval与setTimeout所在的线程
- 定时任务并不是由JS引擎计时的,是由定时触发线程来计时的
- 计时完毕后,通知事件触发线程
-
异步http请求线程- 浏览器有一个单独的线程用于处理AJAX请求
- 当请求完成时,若有回调函数,通知事件触发线程
在前端开发中我们会通过setTimeout/setInterval来指定定时任务,会通过XHR/fetch发送网络请求, 接下来简述一下setTimeout/setInterval和XHR/fetch到底做了什么事
我们知道,不管是setTimeout/setInterval和XHR/fetch代码,在这些代码执行时, 本身是同步任务,而其中的回调函数才是异步任务。
当代码执行到setTimeout/setInterval时,实际上是JS引擎线程通知定时触发器线程,间隔一个时间后,会触发一个回调事件, 而定时触发器线程在接收到这个消息后,会在等待的时间后,将回调事件放入到由事件触发线程所管理的事件队列中。
当代码执行到XHR/fetch时,实际上是JS引擎线程通知异步http请求线程,发送一个网络请求,并制定请求完成后的回调事件, 而异步http请求线程在接收到这个消息后,会在请求成功后,将回调事件放入到由事件触发线程所管理的事件队列中。
当我们的同步任务执行完,JS引擎线程会询问事件触发线程,在事件队列中是否有待执行的回调函数,如果有就会加入到执行栈中交给JS引擎线程执行
宏任务和微任务
- 宏任务:setTimeout,setInterval,Ajax,DOM事件,全局script标签
- 微任务:Promise,async/await
- 先执行宏任务,再执行当前宏任务内的微任务,(在此过程中将遇到的微宏任务依次推入到eventqueue,先进入eventqueue的任务会被先执行)
- 执行完当前宏任务内的所有微任务之后,接着再取出一个宏任务,同样把在此期间产生的回调入队。再把当前的微任务队列清空。以此往复。
- 当然在微宏任务中同步任务会优先执行,而整体的scrpt标签就是第一个执行的宏任务。异步任务包含宏任务和微任务
每个红任务执行过程中,会间隔一次GUI的页面渲染
我们可以将每次执行栈执行的代码当做是一个宏任务(包括每次从事件队列中获取一个事件回调并放到执行栈中执行), 每一个宏任务会从头到尾执行完毕,不会执行其他。
我们前文提到过JS引擎线程和GUI渲染线程是互斥的关系,浏览器为了能够使宏任务和DOM任务有序的进行,会在一个宏任务执行结果后,在下一个宏任务执行前,GUI渲染线程开始工作,对页面进行渲染。
作者:云中桥
链接:juejin.cn/post/684490…
来源:稀土掘金
著作权归作者所有。感谢大佬,仅作记录