面试_Javascript
-
JavaScript 中 call()、apply()、bind() 的用法
var name = '小王',age=17; var obj = { name : '小张', objAge : this.age, myFun : function(fm,t){ console.log(this.name + '年龄' + this.age , "来自" + fm + '去往' + t); } } var db = { name : '德玛', age : 99, } call 、bind 、 apply 这三个函数的第一个参数都是 this 的指向对象,第二个参数有差别 obj.myFun.call(db,'成都','上海'); //德玛年龄99 来自成都去往上海 obj.myFun.apply(db,['成都','上海']);//德玛年龄99 来自成都去往上海 obj.myFun.bind(db,'成都','上海')();//德玛年龄99 来自成都去往上海 obj.myFun.bind(db,['成都','上海'])();//德玛年龄99 来自成都,上海去往undefined
-
谈谈对原型链的理解。
每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。那么假如我们让原型对象等于另一个类型的实例,结果会怎样?显然,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立。如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链的基本概念。
function person(){ console.log('构造函数本身'); console.log({...this}); } var ExamplesPerson = new person();//构造函数实例化 console.log('实例原型',person.prototype); console.log('构造函数实例化对象',ExamplesPerson); console.log('实例化对象原型',ExamplesPerson.__proto__);
-
实现防抖和节流。
防抖是什么?
用户多次点击一个按钮 , 只执行最后一次点击后的事件
function debounce(fn, delay = 200) { let timer = 0 return function() { // 如果这个函数已经被触发了 if(timer){ clearTimeout(timer) } timer = setTimeout(() => { fn.apply(this, arguments); // 透传 this和参数 timer = 0 },delay) } }
节流是什么?
用户多次点击只执行第一次 , 在中间的点击都不生效
function throttle(fn, delay = 200) { let timer = 0 return function () { if(timer){ return } timer = setTimeout(() =>{ fn.apply(this, arguments); // 透传 this和参数 timer = 0 },delay) } }
区别在于 :
防抖 : if(timer){ clearTimeout(timer) } 节流 if(timer){ return }
-
宏任务和微任务
执行顺序 : 同步代码 => 异步(微任务) => 异步(宏任务)
console.log(1); //同步 const promise = new Promise((resolve,reject) => { //同步 console.log(2); resolve() }) function fun(){ console.log(3); } new fun(); //同步 Promise.resolve().then(()=>{ //微任务 console.log('then') }) fun(); //同步 promise.then(()=>{ //微任务 console.log(4); }) setTimeout(() => { //宏任务 console.log(5); }, 0); console.log(6); //同步
结果 : 1 2 3 3 6 then 4 5
-
手写Promise
class MYpromise { //promise 实例
static pending = '待定';
static fulfilled = '成功';
static rejected = '失败';
constructor(fun) {
//构造函数实例化后执行,更改status状态并运行传递进来的函数
this.status = MYpromise.pending; //当前状态为 pending
this.result = null;
this.resolveCallback = [];
this.rejectCallback = [];
try {
fun(this.resolve.bind(this), this.rejcet.bind(this));
} catch (error) { //防止运行报错
this.rejcet(error)
}
}
resolve(result) {
console.log('1.resolve执行', this.status);
setTimeout(() => { //添加定时器 将resolve添加到事件末尾执行
if (this.status === MYpromise.pending) {
this.status = MYpromise.fulfilled; //更改状态为 resolve
this.result = result; //resolve('赋值resolve传递的值')
this.resolveCallback.forEach(callback => {//调用pending状态储存下来的函数
callback(result);
})
console.log('2.resolve执行', this.status);
}
})
}
rejcet(result) {
console.log('reject执行', this.status);
setTimeout(() => {
if (this.status === MYpromise.pending) {
this.status = MYpromise.rejected; //更改状态为 reject
this.result = result; //resolve('赋值reject传递的值')
this.rejectCallback.forEach(callback => {
callback(result);
})
}
})
}
then(onFulfilled, onRejected) {
return new MYpromise((resolve, reject) => {
onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : () => {};
onRejected = typeof onRejected === 'function' ? onRejected : () => {};
console.log('then执行', this.status);
if (this.status === MYpromise.pending) {
console.log('then执行缓存函数', this.status);
this.resolveCallback.push(value =>{
const res = onFulfilled(value); //核心代码 反复执行运行.then传递进来的函数
// console.log('onFulfilled',onFulfilled);
// console.log(value);
if(res instanceof MYpromise){
res.then(resolve)
}else{
resolve(res);
}
})
}
if (this.status === MYpromise.fulfilled) {
setTimeout(() => {
onFulfilled(this.result)
console.log('then执行', this.status);
});
}
if (this.status === MYpromise.rejected) {
setTimeout(() => {
onRejected(this.result);
});
}
})
}
}
console.log('第一步'); //promise运行 let myPromise = new MYpromise((resolve, reject) => { console.log('第二步'); setTimeout(() => { resolve('第四步resolve成功'); console.log('第四步') }) // reject('目的失败了 函数状态更改为reject'); }) myPromise .then(res => { console.log(res); return '第五步' } ) .then(res =>{ console.log(res); return '第六步'; }) .then(res =>{ console.log(res); return '第七步'; }).then(res =>{ console.log(res); }) console.log('第三步')
1. 执行第一步打印
2. 构造函数实例化,运行constructor函数
更改状态为 pending 运行实例化的时候传递进去的函数,并改变this指向为MYpromise内部 ----pending
3. 执行第二步打印
遇到setTimeout 异步(宏任务) , 将setTimeout加入宏任务队列 等待执行
调用.then函数 , 此时then函数返回个自定义MYPromise构造函数并实例化
if判断当前状态为pending 对.then传递的函数存储在数组 resolveCallback
.then链式调用 , 有多少次.then有多少次就创建多少次 MYpromise
4. 执行同步任务 第三步打印 至此同步任务执行完毕
5. 开始执行宏任务队列 setTimeout
执行resolve 遇到里面还有个setTimeout再次加入宏任务往下执行
6. 执行第四步打印
7. 再次运行宏任务队列 resolve里的setTimeout
判断当前状态为 pending 更改为 fulfilled ----fulfilled
接收到 resolve 传递进来的值
运行在 .then 的时候存储起来 传递给 .then的回调函数
把在运行 new MYpromise 的时候 resolve 里面的参数传递给.then并运行函数
.then函数接受到 resolve 传递的值 并打印出来
8. 打印第四步resolve成功
执行完毕后再次调用 resolve
9. 再次执行当前的.then 重复 7 - 8 操作直至运行完在 MYPromise.then阶段创建的.then