目录
闭包
类的继承与创建
如何解决回调地狱
事件委托
说一下图片的懒加载和预加载
mouseover和mouseenter的区别
js的new操作符做了哪些事情
改变函数内部this指针的指向函数(bind,apply,call的区别)
js的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的区别?
异步加载JS的五种方式
js节流和防抖
js垃圾回收机制
Commonjs、AMD和CMD
浅拷贝与深拷贝
将原生的ajax封装成promise
实现两列等高
代码的执行顺序
如何实现sleep的效果
js判断数据类型
js数组常用方法
数组去重
性能优化
JS的语言特性
判断变量是数组Array类型
函数柯里化
箭头函数 可以new吗
立即执行函数
js函数重载
fetch
RESTful
31. echarts底层原理
- WebSocket
1. 闭包
闭包是指有权访问另一个函数作用域中的变量的函数;
function aaa(){
var name = "xxx"
return function bbb(){
alert(name);
}
}
常见的定时器问题
for( var i = 0; i < 5; i++ ) {
setTimeout(() => {
console.log( i );
}, 1000)
}
setTimeout函数在当前执行队列的最后执行,获取到的i是最外部作用域的i=5,所以得到5个5
那么如果想1s后得到0-4怎么做?在for循环内创建闭包
for (var i = 0; i < 5; i++) {
(function(j) {
setTimeout(function() {
console.log(j);
},1000)
})(i)
}
同样setTimeout在执行队列的最后执行,获取到的j是外部函数的j,由于闭包中的变量会保存下来,每一次获取的j分别是0,1,2,3,4
由于闭包会常驻内存,使用不当会导致内存溢出
2. 继承
3. 如何解决回调地狱
1. 拆解function:将各步拆解为单个的function
function buildCatList(list, returnVal, fn) {
setTimeout(function (name) {
var catList = list === '' ? name : list + ',' + name
fn(catList)
}, 200, returnVal)
}
buildCatList('', 'Panther', getJanguar)
function getJanguar(list) {
buildCatList(list, 'Janguar', getLynx)
}
function getLynx(list) {
buildCatList(list, 'Lion', print)
}
function print(list) {
console.log(list)
}
// Panther,Janguar,Lion
2. 事件发布/监听模式
一方面,监听某一事件,当事件发生时,进行相应回调操作;另一方面,当某些操作完成后,通过发布事件触发回调,这样就可以将原本捆绑在一起的代码解耦。
3.通过 Promise 链式调用的方式
function buildCatList(list, returnVal) {
return new Promise(function (resolve, reject) {
setTimeout(function (name) {
var catList = list === '' ? name : list + ',' + name
resolve(catList)
}, 200, returnVal)
})
}
buildCatList('', 'Panther').then(function (res) {
return buildCatList(res, 'Janguar')
}).then(function (res) {
return buildCatList(res, 'Lion')
}).then(function (res) {
console.log(res)
})
// Panther,Janguar,Lion
Promise 函数虽然改变了之前回调地狱的写法,但是在根本上还是函数套函数,看起来不是那么的美观
4.通过 Generator 函数暂停执行的效果方式
function getPanther(list) {
return list + 'Panther' + ','
}
function getJaguar(list) {
return list + 'Jaguar' + ','
}
function getLion(list) {
return list + 'Lion'
}
function* buildCatList() {
yield getPanther
yield getJaguar
yield getLion
}
//流程控制
function run(fn){
const gen = fn() // 调用 Generator 函数,返回一个遍历器对象 (Iterator)
var a = gen.next().value('') // 调用遍历器对象的 next() 方法,就会返回一个有着 value 和 done 两个属性的对象
var b = gen.next().value(a)
var c = gen.next().value(b)
console.log(c)
}
run(buildCatList) // 开始执行
// Panther,Jaguar,Lion
通过 generator 虽然能提供较好的语法结构,但是毕竟 generator 与 yield 的语境用在这里多少还有些不太贴切
5.通过ES8的异步函数 async / await
- async 表示这是一个 async 函数,await 只能用在这个函数里面
- await 表示在这里等待 Promise 返回结果后,再继续执行
- await 后面跟着的应该是一个 Promise 对象(当然,其他返回值也没关系,只是会立即执行)
- await 等待的虽然是 Promise 对象,但不必写 .then() ,可以直接得到返回值
function buildCatList(list, returnVal) {
return new Promise(function (resolve, reject) {
setTimeout(function (name) {
var catList = list === '' ? name : list + ',' + name
resolve(catList)
}, 200, returnVal)
})
}
function fn(list) {
return list + ',' + 555
}
async function render() {
var a = await buildCatList('','Panther')
var b = await buildCatList(a, 'Jaguar')
var c = await buildCatList(b, 'Lion')
var d = await fn(c)
console.log(d)
}
render()
// Panther,Jaguar,Lion,555
代码简洁清晰,异步代码也具有了“同步”代码的结构
4. 事件委托
简介:事件委托指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。
举例:最经典的就是ul和li标签的事件监听,比如我们在添加事件时候,采用事件委托机制,不会在li标签上直接添加,而是在ul父元素上添加。
好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制。
5. 说一下图片的懒加载和预加载
预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。
懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。
两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。
懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
6. mouseover和mouseenter的区别
mouseover:当鼠标移入元素或其子元素都会触发事件,所以有一个重复触发,冒泡的过程。对应的移除事件是mouseout
mouseenter:当鼠标移除元素本身(不包含元素的子元素)会触发事件,也就是不会冒泡,对应的移除事件是mouseleave
7. js的new操作符做了哪些事情
new共经过了4个阶段
1.创建一个空对象
var obj = new Object();
2. 设置原型链(当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象)
obj.__proto__= Func.prototype;
3.让Func中的this指向obj,并执行Func的函数体。(创建新的对象之后,将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
var result =Func.call(obj);
4. 判断Func的返回值类型:
如果是值类型,返回obj。如果是引用类型,就返回这个引用类型的对象
if (typeof(result) == "object"){
func=result;
}
else{
func=obj;;
}
默认情况下函数返回值为undefined,即没有显示定义返回值的话,但构造函数例外,new构造函数在没有return的情况下默认返回新创建的对象。
但是,在有显示返回值的情况下,如果返回值为基本数据类型{string,number,null,undefined,Boolean},返回值仍然是新创建的对象。
只有在显示返回一个非基本数据类型时,函数的返回值才为指定对象。在这种情况下,this所引用的值就会被丢弃了
8.改变函数内部this指针的指向函数(bind,apply,call的区别)
call()的用法
var obj = {
text: '我的两个爱好有:'
}
function getHobby(a, b) {
console.log(this.text + a + '和' + b)
}
getHobby.call(obj, '足球', '羽毛球')
// 我的两个爱好有:足球和羽毛球
apply()的用法
var obj = {
text: '我的两个爱好有:'
}
function getHobby(a, b) {
console.log(this.text + a + '和' + b)
}
getHobby.apply(obj, ['足球', '羽毛球'])
// 我的两个爱好有:足球和羽毛球
bind()的用法
var obj = {
text: '我的两个爱好有:'
}
function getHobby(a, b) {
console.log(this.text + a + '和' + b)
}
getHobby.bind(obj, '足球', '羽毛球')()
// 我的两个爱好有:足球和羽毛球
1.三者的第一个参数,都是this的指向。
- call和bind在第一个参数后面传入的是一个参数列表。而 apply的第二个参数为参数数组。
- call和apply是立即调用。而bind返回对应函数,需要自己再调用()。
9. js的各种位置,比如clientHeight,scrollHeight,offsetHeight ,以及scrollTop, offsetTop,clientTop的区别?
clientHeight:表示的是可视区域的高度,不包含border和滚动条
offsetHeight:表示可视区域的高度,包含了border和滚动条
scrollHeight:表示了所有区域的高度,包含了因为滚动被隐藏的部分。
clientTop:表示边框border的厚度,在未指定的情况下一般为0
scrollTop:滚动后被隐藏的高度,获取对象相对于由offsetParent属性指定的父坐标(css定位的元素或body元素)距离顶端的高度。
10. 异步加载JS的五种方式
1.