年关将近,金三银四跳槽季要来了,开始整理面试题前端
基本类型有七种面试
null
undefined
boolean
number
string
symbol
(较新标准)BigInt
(新标准)NaN
也属于 number
类型,而且 NaN
不等于自身数组
栈内存
中的简单数据段不可变的
Array.prototype.sort.call('abc');
(会报错)__proto__
没有属性
基本包装类型
访问的属性/方法// 经过包装类型访问基础类型特性
let str = 'abc';
console.log(str.length)
// 当你调用 `str.length` 时,实际过程是这样的:
// -> 建立String类型的一个实例
// -> 在实例上调用指定的方法
// -> 销毁这个实例
let _str = new String(str);
let len = _str.length;
_str = null;
复制代码
typeof
,可是 typeof null === 'object'
null
是基础类型,不是 Objecttypeof
检测null会产生BUG// 借鉴 Vue 源码的 object 检测方法
function isObject (obj: any): Boolean {
return obj !== null && typeof obj === 'object'
}
复制代码
Object.prototype.toString.call
(万能方法)
[[class]]
[object type]
// 借鉴 Vue 源码的检测方法
let _toString = Object.prototype.toString;
function toRawType (value: any): String {
// 获取 从第九个到倒数第二个 字符
// 好比 [object String] 获取 String
return _toString.call(value).slice(8, -1)
}
复制代码
valueOf
,而后调用 toString
。(这两个方法能够被重写)+
其余操做都会以数字进行计算,若是是 +
运算,若是不是全部字面量都是number
(都是number就是数字的加法咯),那么会转换为字符串(toString
)进行拼接遵循IEEE 754 双精度版本(64位)
标准的语言都有的问题。计算机没法识别十进制,JS会将十进制转换为对应的二进制(二进制即:0
和 1
)。bash
那么 怎么用 0
和 1
来表示 0.1
和 0.2
呢?微信
console.log(0.1.toString(2));
// -> 0.0001100110011001100110011001100110011001100110011001101
console.log(0.2.toString(2));
// -> 0.001100110011001100110011001100110011001100110011001101
复制代码
这样看似没问题啊。为何会有BUG呢?函数
别忘了:JS的精确度区间 约为正负 2^53
,超出限制会截断。因此你看到的 0.1 不是真的 0.1。ui
先乘再除
BigInt
(兼容性不好)JS中除了 "假" 值之外就是 "真" 值。this
"假"值包括 7 个spa
undefined
null
false
NaN
''
0
-0
在条件判断的隐式转换中:"假" 值会转换为 false
,"真" 值会转换为 true
;prototype
两个空间
堆
上,储存引用类型自己的数据(固然数据量会比较大)栈
上,储存对堆
上数据的引用(存储堆上的内存地址,也就是指针)let a={}; a.x=1;
Object.prototype.toString.call
检测 [[class]]
instanceof
判断引用类型constructor
判断引用类型(constructor
是可写的,慎用)instanceof
内部机制是经过判断对象的原型链中是否是能找到对应的的prototype
因此在验证iframe时会有BUG,由于 window.Array.prototype !== window.frames[0].Array.prototype
,因此不存在继承关系
// 实现 instanceof
function instanceof(obj, target) {
// 得到对象的原型
obj = obj.__proto__
// 判断对象的类型是否等于类型的原型
while (true) {
// 若是__proto__ === null 说明原型链遍历完毕
if (obj === null) {
return false
}
// 若是存在 obj.__proto__ === target.prototype
// 说明对象是该类型的实例
if (obj === target.prototype) {
return true
}
// 原型链上查找
obj = obj.__proto__
}
}
复制代码
会返回 false
由于基础类型没有 __proto__
let str = '123';
console.log(str instanceof String) // -> false
复制代码
可是若是更改了 静态方法Symbol.hasInstance
就能够判断了
class StringType {
static [Symbol.hasInstance](val) {
return typeof val === 'string'
}
}
console.log(str instanceof StringType) // -> true
复制代码
数组是一种类列表对象,其数据在内存中也能够不连续
数组应该是一段线性分配的内存,可是JS的Array的检索和更新方式和对象如出一辙
Array.prototype
,向上再继承自Object.prototype
let obj = {
'2': 3,
'3': 4,
'length': 2,
'splice': Array.prototype.splice,
'push': Array.prototype.push
}
obj.push(1)
obj.push(2)
console.log(obj);
// Object(4) [empty × 2, 1, 2, splice: ƒ, push: ƒ]
复制代码
delete arr[2]
,并不能减小length,而只是删除了对应的属性(变成empty)Array.isArray()
会返回 false
Array.from
能够转换为数组常常碰见的类数组
arguments
...args
代替,这样不定参数就是真数组PS: 感谢 @沉末_ 的补充
类型转换都是先 valueOf
再 toString
;
右边
!
优先级比 ==
高,先执行 !
![]
获得 falsefalse
转化为数字 0
左边
[].valueOf()
原始值 仍是 []''
转化为数字 0
因此:0 == 0
,答案是 true
验证:
let arr1 = [];
let arr2 = [];
console.log(arr1 == !arr2) // -> true
arr1.toString = () => {
console.log(111)
return 1
}
console.log(arr1 == !arr2)
// -> 111
// -> false
复制代码
===
不进行隐式转换==
会进行隐式转换
{a: 1} == "[object Object]"
左边会执行 .toString()
依然是类型转换逻辑:基础类型经过 valueOf
进行隐式转换
更改 valueOf
方法就能够实现
let a = {
value: 0,
valueOf: function() {
this.value++;
return this.value;
}
};
console.log(a == 1 && a == 2);
复制代码
Object.is
和 === 的区别 ?Object.is(v1, v2)
修复了 ===
的一些BUG (-0和+0, NaN和NaN)
:
// === 案例
-0 === +0 // -> true
NaN !== NaN // -> false
Object.is(-0, +0) // -> false
Object.is(NaN, NaN) // -> true
复制代码