1、为什么typeof null 是object?
不同的数据类型在底层都是通过二进制表示的,二进制前三位为000
则会被判断为object
类型,
而null底层的二进制全都是0,那前三位肯定也是000
,所以被判断为object
2、0.1 + 0.2 === 0.3,对吗?不对
JavaScript的计算存在精度丢失问题
- 原因:JavaScript中小数是浮点数,需转二进制进行运算,有些小数无法用二进制表示,所以只能取近似值,所以造成误差
- 解决方法:
- 先变成整数运算,然后再变回小数
- toFixed() 性能不好,不推荐
3、addEventListence的第三个参数是干嘛的?
xxx.addEventListence(‘click’, function(){}, false)
第三个变量传一个布尔值,需不需要阻止冒泡,默认是false,不阻止冒泡
4、Ajax、Axios、Fetch有啥区别?
- Ajax:是对XMLHttpRequest对象(XHR)的封装
- Axios:是基于Promise对XHR对象的封装
- Fetch:是window的一个方法,也是基于Promise,但是与XHR无关,不支持IE
5、load、$(document).ready、DOMContentLoaded的区别?
DOM文档加载的步骤为:
- 1、解析HTML结构。
- 2、加载外部脚本和样式表文件。
- 3、解析并执行脚本代码。
- 4、DOM树构建完成。//
DOMContentLoaded
触发、$(document).ready
触发 - 5、加载图片等外部文件。
- 6、页面加载完毕。//
load
触发
6、如何实现数组去重?
// 使用 Map 去重
function quchong1(arr) {
const newArr = []
arr.reduce((pre, next) => {
if (!pre.get(next)) {
pre.set(next, 1)
newArr.push(next)
}
return pre
}, new Map())
return newArr
}
// 使用 Set 去重
function quchong (arr) {
return […new Set(arr)]
}
7、call、apply、bind改变this
const obj1 = {
name: ‘林三心’,
sayName: function() {
console.log(this.name)
}
}
const obj2 = {
name: ‘Sunshin_Lin’
}
// 改变sayName的this指向obj2
obj1.sayName.call(obj2) // Sunshin_Lin
// 改变sayName的this指向obj2
obj1.sayName.apply(obj2) // Sunshin_Lin
// 改变sayName的this指向obj2
const fn = obj1.sayName.bind(obj2)
fn() // Sunshin_Lin
8、BOM 和 DOM 的关系
BOM全称Browser Object Model,即浏览器对象模型,主要处理浏览器窗口和框架。
DOM全称Document Object Model,即文档对象模型,是 HTML 和XML 的应用程序接口(API),遵循W3C 的标准,所有浏览器公共遵守的标准。
JS是通过访问BOM(Browser Object Model)对象来访问、控制、修改客户端(浏览器),由于BOM的window包含了document,window对象的属性和方法是直接可以使用而且被感知的,
因此可以直接使用window对象的document属性,通过document属性就可以访问、检索、修改XHTML文档内容与结构。因为document对象又是DOM的根节点。
可以说,BOM包含了DOM(对象),浏览器提供出来给予访问的是BOM对象,从BOM对象再访问到DOM对象,从而js可以操作浏览器以及浏览器读取到的文档。
9、JS中的substr()和substring()函数有什么区别
substr()函数的形式为substr(startIndex,length)。 它从startIndex返回子字符串并返回’length’个字符数。
var s = “hello”;
( s.substr(1,4) == “ello” ) // true
substring()函数的形式为substring(startIndex,endIndex)。 它返回从startIndex到endIndex - 1的子字符串。
var s = “hello”;
( s.substring(1,4) == “ell” ) // true
10、Object和Map的区别
JavaScript 的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
const m = new Map();
const o = {p: ‘Hello World’};
m.set(o, ‘content’)
m.get(o) // “content”
m.has(o) // true
m.delete(o) // true
m.has(o) // false
将对象o
当作m
的一个键,然后又使用get
方法读取这个键,接着使用delete
方法删除了这个键。
const map = new Map([
[‘name’, ‘张三’],
[‘title’, ‘Author’]
]);
map.size // 2
map.has(‘name’) // true
map.get(‘name’) // “张三”
map.has(‘title’) // true
map.get(‘title’) // “Author”
Map 也可以接受一个数组作为参数。该数组的成员是一个个表示键值对的数组。
const map = new Map();
map.set([‘a’], 555);
map.get([‘a’]) // undefined
上面代码的set
和get
方法,表面是针对同一个键,但实际上这是两个不同的数组实例,内存地址是不一样的,因此get
方法无法读取该键,返回undefined
。
const map = new Map();
const k1 = [‘a’];
const k2 = [‘a’];
map
.set(k1, 111)
.set(k2, 222);
map.get(k1) // 111
map.get(k2) // 222
Map 的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键。
这就解决了同名属性碰撞(clash)的问题,我们扩展别人的库的时候,如果使用对象作为键名,就不用担心自己的属性与原作者的属性同名。
let map = new Map()
.set(1, ‘a’)
.set(2, ‘b’)
.set(3, ‘c’);
set
方法返回的是当前的Map
对象,因此可以采用链式写法。
11、weakMap
WeakMap
只接受对象作为键名(null
除外),不接受其他类型的值作为键名
用途:
let myWeakmap = new WeakMap();
myWeakmap.set(
document.getElementById(‘logo’),
{timesClicked: 0})
;
document.getElementById(‘logo’).addEventListener(‘click’, function() {
let logoData = myWeakmap.get(document.getElementById(‘logo’));
logoData.timesClicked++;
}, false);
上面代码中,document.getElementById('logo')
是一个 DOM 节点,每当发生click
事件,就更新一下状态。
我们将这个状态作为键值放在 WeakMap 里,对应的键名就是这个节点对象。一旦这个 DOM 节点删除,该状态就会自动消失,不存在内存泄漏风险。
12、(a == 1 && a == 2 && a ==3) 有可能是 true 吗?
当两个类型不同时进行==比较时,会将一个类型转为另一个类型,然后再进行比较。
比如Object
类型与Number
类型进行比较时,Object
类型会转换为Number
类型。
Object
转换为Number
时,会尝试调用Object.valueOf()
和Object.toString()
来获取对应的数字基本类型。