一、javascript
的基本数据类型
基本数据类型:Number
、String
、Boolean
、undefined
、null
、Symbol
引用数据类型:Object
、Array
、RegExp
、Date
、Function
,特殊的基本包装类型(Number
、String
、Boolean
)、以及单体内置对象(Global
、Math
等)
二、如何判断不同的javascript
数据类型
-
typeof
:typeof x
,基本类型除null
返回object
,其余全部返回自身的数据类型;引用类型除Function
返回function
,其余全部返回object
-
instanceof
:A instanceof B
,用来判断A是否是B的实例,检测的是原型,而不是属于那种类型 -
toString
:是用Object.prototype.toString.call(xxx)
Object.prototype.toString.call('qqq') // [object String]
三、undefined
和null
有什么区别
undefined
:表示缺少值,应该有值但还未赋值
- 变量被声明了,但没有赋值时,就等于
undefined
- 调用函数时,应该提供函数参数而没有提供事,参数等于
undefined
- 对象没有赋值的属性,值为
undefined
- 函数没有返回值时,默认返回
undefined
null
:表示没有值,不应该有值
- 作为函数参数,表示该函数的参数不是对象
- 作为对象原型链的终点
四、数组对象有哪些常用方法
修改器方法:修改原始数组
pop()
:删除数组最后一个元素,并返回这个元素shift()
:删除数组第一个元素,并返回这个元素unshift()
:在数组的开头增加一个或多个元素,并返回数组的新长度push()
:在数组的末尾增加一个或多个元素,并返回数组的新长度reverse()
:对数组进行逆序排序sort()
:对数组进行排序并返回当前数组splice()
:在任意位置给数组删除或者添加元素
访问器方法:不修改原始数组
concat()
:返回一个组合而成的数组join()
:拼接数组元素形成一个字符串slice()
:截取当前数组中的一段元素组成一个新数组indexOf()
:返回数组中第一个与指定值相等的元素的索引,找不到则返回-1lastIndexOf()
:从数组最后一个元素往前找与指定值相等的元素的索引,找不到则返回-1forEach()
:为数组的每一个元素执行一次回调,最终返回undefined
every()
:为数组的每一个元素都满足测试函数,则返回true
,否则返回false
some()
:数组中只要有一个函数满足测试条件,则返回true
,否则返回false
filter()
:将所有在过滤函数中返回true
的元素组成一个新数组返回map()
:返回一个由回调函数的返回值组成的新数组
五、javascript
创建对象的方式
-
对象字面量
let obj = {}
-
new Object
构造函数let obj = new Object()
-
工厂模式
function Person(name,age){ var o = new Object() o.name = name o.age = age o.say = function(){ console.log(o.name) } return o } let person = Person('hello',18)
缺点:每次通过
Person
创建对象时,所有的say
方法都是一样的,但是却存储了多次,造成资源浪费 -
构造函数模式
function Person(name,age){ this.name = name this.age = age this.say = function(){ console.log(this.name) } } let person = new Person('hello',18)
缺点:这个模式隐式在最后
return this
,如果在创建对象的时候缺少new
,那么在函数中的this
指向window
,添加为全局属性和方法,解决办法是根据return this
的特性调用call
或者apply
指定this
-
原型模式
function Person(){ Person.prototype.name = 'hello' Person.prototype.say = function(){ console.log(this.name) } } Person.prototype.friends = ['lili'] let person = new Person()
缺点:实现方法与属性的共享,可以动态添加属性,但没有办法创建实例自己的属性和方法,也没有办法传递参数
-
构造函数和原型结合
function Person(name,age){ this.name = name this.age = age } Person.prototype.say = function(){ console.log(this.name) } let person = new Person('hello',18)
六、怎么实现对对象的深拷贝和浅拷贝
区别JavaScript的浅拷贝和深拷贝并掌握两者的实现方法
七、什么是闭包,为什么要使用闭包
八、介绍一下javascript
原型,原型链,两者有何特点
九、javascript
如何实现继承
十、new
操作符具体都干了什么
-
创建一个空对象
let obj = new Object()
-
链接到函数的原型
obj.__proto__ = Func.prototype
-
属性和方法都被加入到
this
引用的对象中,绑定this
let result = Func.call(this)
-
最后隐式的返回对象
this
return result
十一、同步和异步的区别,怎么异步加载javascript
同步模式:同步模式又称为阻塞模式,默认情况下javascript
是会阻塞加载的,当前面的javascript
请求没有处理和执行完时,会阻止浏览器后续代码的处理
异步模式:异步模式又称为非阻塞模式,浏览器在下载执行javascript
的同时,还会继续执行后续页面的处理
异步加载javascript
:
- 动态添加
script
标签 - 给标签添加
defer
或者async
属性,两者均能实现异步加载defer
:加载完之后会等html加载完毕之后再执行async
:在异步加载完马上开始执行
十二、跨域问题的产生,如何解决
十三、对this
的理解
研究this
一般都是this
的指向问题,核心就是**this
永远指向调用它的对象**,除非改变this
指向或者是箭头函数等特殊情况,在普通模式下,最外层的this
指向window
,严格模式下this
指向undefined
十四、apply()
、call()
、bind()
是做什么的,有什么区别
相同点:改变this
指向
不同点
-
apply()
:传入两个参数,第一个是作为函数的执行上下文,另一个是作为函数参数数组let obj = {name:'haha'} function func(firstName,lastName){ console.log(firstName + this.name + lastName) } func.apply(obj,[1,2]) // 1haha2
-
call()
:传入两部分参数,第一个参数是作为函数的执行上下文,剩下部分是个列表,可接受多个参数let obj = {name:'haha'} function func(firstName,lastName){ console.log(firstName + this.name + lastName) } func.call(obj,'1','2') //1haha2
-
bind()
:传入两部分参数,第一个参数是作为函数的执行上下文,剩下部分是个列表,可接受多个参数let obj = {name:'haha'} function func(){ console.log(this.name) } let funcx = func.bind(null,'xixi') funcx() // xixi
apply
和call
都会调用函数立即执行,bind
不会立即执行,而是返回一个改变上下文this
指向的函数,原函数中的this
没有改变;bind
在传递参数的时候会将自己带过去的参数排在原函数参数之前
function func(a,b,c){
console.log(a,b,c)
}
let funcx = func.bind(this,'xixi')
funcx(1,2) // xixi12
十五、什么是内存泄漏、内存溢出,哪些操作会造成内存泄漏
内存溢出:程序运行时需要的内存超过了剩余内存,造成内存溢出
内存泄漏:指一块被分配的内存既不能使用也不能回收,直到浏览器进程结束( 占用的内存没有及时释放 )
操作:闭包、循环引用、意外的全局变量、未被及时清理的定时器或者回调函数
十六、什么是事件代理,原理是什么
事件代理:将元素的事件委托给它的父级或者更外层的元素处理
原理:利用事件的冒泡机制实现的
优点:只需要将同类元素的事件委托给父级或者更外层的元素,不需要给所有的元素都绑定一个事件,减少内存占用和代码量,提升性能;且动态新增的元素无需重新绑定事件
十七、对AMD
、CMD
的理解,有什么区别
两者都是为了解决浏览器模块化的问题而产生的
AMD
:对应库函数Require.js
,异步加载模块, 推崇依赖前置 ,默认API
是一个当多个用,擅长在浏览器端
CMD
:对应库函数Sea.js
,同步加载模块, 推崇依赖就近 ,API
严格区分,推崇职责单一,擅长在服务器端
十八、对ES 6
的了解
新增特性
- 声明变量的方式
let
const
- 变量赋值解构
- 字符串新增方法:
includes()
、startsWith()
、endsWidth()
等 - 数组新增方法:
Array.from()
、Array.of()
、entries()
、keys()
、values()
等 - 对象的简洁写法,新增方法
Object.is()
、Object.assign()
、entries()
、keys
等 - 箭头函数、扩展运算符、函数参数默认值等
- 新的数据结构:
Map
、Set
Proxy
代理Promise
对象async
函数、await
命令class
类module
体系模块的加载和输出方式
十九、箭头函数有什么特点
ES 6
中允许使用箭头函数,特点如下:
- 函数体中的
this
对象,是定义时所在的对象,而不是调用时的对象 - 不可以当作构造函数,即不可使用
new
命令 - 不可以使用
arguments
对象,因为不存在,如果要用,可以使用rest
对象(扩展运算符)
二十、Promise
对象的了解
二十一、async
函数和await
命令
async
函数:就是Generator
函数的语法糖
async
函数返回一个Promise
对象,可以使用then
方法添加回调函数。当函数执行时,遇到await
命令就会先返回,等异步操作完成,再接着执行函数体内后面的语句async
函数内部return
语句返回的值,会成为then
方法回调函数的参数async
函数返回的Promise
对象,必须等到内部所有await
命令后面的Promise
对象执行完,才会发生状态改变,除非遇到return
语句或者抛出错误async
函数内部抛出错误,会导致返回的Promise
对象变为reject
状态。抛出的错误对象会被catch
方法回调函数接收到
function timeout(ms){
return new Promise((resolve) => {
setTimeout(resolve,ms)
})
}
async function asyncFun(value,ms){
await timeout(ms)
console.log(value)
}
asyncFun('hello',1000)
console.log('会不会阻塞函数体外的代码执行')
//会不会阻塞函数体外的代码执行
//Promise {<pending>}
//hello
await
命令:await
命令后面是一个promise
对象,返回该对象的结果;如果不是promise
对象,直接返回对应的值;另一种情况是如果then
方法后面是一个thenable
对象,则等同于promise
对象
await
命令后面是一个promise
对象,运行结果可能是rejected
,所以最好把await命令放在try...catch
代码块中- 多个
await
命令后面的异步操作,如果不存在继发关系,最好同时触发 await
命令只能用在async
函数中,否则会报错
二十二、export
与export default
的区别
两者均可用于常量、对象、函数、文件、模块等的导出
区别 | export | export default |
---|---|---|
导出区别 | 在一个文件或者模块中导出,export 、import 可以有多个 | export default 只有一个 |
导入区别 | 在别的文件导入,变量名不可更改,且需加{} | 在别的文件导入,变量名可随意更改,不用加{} |
二十三、前端性能优化
措施 | 解释 |
---|---|
1、尽可能减少 http 请求 | 减少请求速度就快,合并css 、js ,背景图使用css sprites |
2、使用CDN | 就近访问服务器,较少数据在网络上传输的时间 |
3、添加Expires 头或者Cache-control | 使用缓存 |
4、压缩组件 | 减少文件传输体积大小 |
5、将css 样式放在页面上 | 有些浏览器比如IE 、FireFox 要等全部css 加载完毕之后才会去渲染页面 |
6、将script 脚本移到底部 | 会阻塞页面的下载,阻塞并行下载数量 |
7、避免使用css 中的Expressions | 避免使用表达式,减少执行时间 |
8、将javascript 和css 独立成外部文件 | 如果做了缓存那就减少次数请求了,而且还便于维护 |
9、减少DNS 查询 | 域名和ip 地址之间的转换工作,称为域名解析也称为DNS 查询,一次查询要耗费20~120ms ,在查询结束前,不会下载该域名的任何东西,所以建议一个页面包含的域名数尽量控制在2~4 个 |
10、压缩javascript 和css | 减少体积,传输就快,显而易见(但是可读性没了) |
11、避免重定向 | 会减少 web 请求 |
12、移除重复脚本 | 减少体积 |
13、配置实体标签ETags | 不懂,听说可以减少web应用带宽和负载 |
14、使ajax 缓存 | 无解释 |
二十四、对 JS 引擎执行机制的理解
明确两点:
javascript
是单线程语言javascript
的事件循环(event loop)是javascript
的执行机制
javascript
将任务分为同步任务和异步任务,执行机制就是代码执行开始,遇到同步任务就依次放到主线程上,遇到异步任务就先放到任务队列中,等同步任务执行完毕之后,通过事件循环去轮询可执行的异步任务,则把它加入到主线程上执行
区分宏任务和微任务
宏任务:setTimeout
、setInterval
、requestAnimationFrame
、I/O
微任务:process.nextTick
、Promise
、Object.observe
、MutationObserver
执行顺序:先同再异,先微再宏
二十五、for in
和for of
区别
for in
:遍历的是key
for of
:遍历的是key
对应的值 (对象使用for of
会报obj is not iterable
的错误)