【前端面试】五、JavaScript 6-10

【前端面试】五、JavaScript 6-10

目录

【前端面试】五、JavaScript 6-10

6. this指向

7. 箭头函数

8. 防抖和节流

9. promise

10.  async


6. this指向

6.1 this的绑定

  • 默认绑定:全局环境中,this默认绑定到window
  • 隐式绑定:this隐式绑定到函数调用时的直接对象。隐式丢失:被隐式绑定的函数丢失绑定对象
  • 显式绑定:通过call()、apply()、bind()方法把对象绑定到this上
  • new绑定:new构造函数调用的this绑定

6.2 改变this指向

call、apply、bind、外部变量闭包、箭头函数(没有自己的this,指向所定义时的上下文)

6.3 call()、apply()、bind()

apply、call:都能改变this指向并立即执行函数fn,但传入的参数形式不同

bind:改变this指向并返回一个新的函数,这个函数不会马上执行

  • fn.apply(作用域对象,[参数1,参数2])
  • fn.call(作用域对象,参数1,参数2)
  • fn.bind(作用域对象,参数1,参数2)

// 手写call方法
Function.prototype.mycall = function(obj) {
    if(typeof this !== "function"){
        throw new Error("error");
    }
    
    obj = obj || window; // 设置对象obj
    obj.fn = this; // 给对象添加方法fn, this 指向fn
    let arg = [...arguments].splice(1); // 取参数a, b
    let result = obj.fn(...arg); // 执行对象的方法fn
    return result;
}
fn.mycall(obj, a, b)

// 手写apply方法
Function.prototype.apply = function (context, argsArr) {
  if(typeof this !== "function"){
      throw new Error("error");
  }
    
  context = context || window;
  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;
  
  context[fnSymbol](...argsArr);
  delete context[fnSymbol];
}

// bind
Function.prototype.bind = function (context, ...args) {
  if(typeof this !== "function"){
      throw new Error("error");
  }
    
  context = context || window;
  const fnSymbol = Symbol("fn");
  context[fnSymbol] = this;
  
  return function (..._args) {
    args = args.concat(_args);
    
    context[fnSymbol](...args);
    delete context[fnSymbol];   
  }
}

Function.prototype.bind2 = function(context){
    var self = this;
    var args = Array.prototype.slice.call(arguments,1);
    var fNOP = function(){};
    var fbound = function(){
        self.apply(this instanceof self ? this:context,
        args.concat(Array.prototype.slice.call(arguments)));
    }
    fNOP.prototype = this.prototype;
    fbound.prototype = new fNOP();
    return fbound;
}

7. 箭头函数

  • 箭头函数中的this指向所定义时上下文中的this(沿作用域链向上查找),而不是调用时所在的对象;
let str = 'global';
let obj = {
    str: 'private',
    getStr: function(){
        console.log(this.str); // this指向obj
    }
}
obj.getStr(); // private

let str = 'global';
let obj = {
    str: 'private',
    getStr: () => {
        console.log(this.str);  // this指向window
    }
}
obj.getStr(); // global

  • 不可以用作构造函数,不能使用new命令,否则报错,没有new.target值;
const Person = (name) => {
    this.name = name
}
let tom = new Person('Tom') // Person is not a constructor

  • 没有arguments对象,可用...rest参数代替;
const fn = () => {
	console.log(arguments);// arguments is not defined
}
fn(1, 2, 3)

  • 没有原型对象prototype
function fun() {}
fun.prototype

const fn = () => {}
fn.prototype

8. 防抖和节流

防抖:多次触发事件后,事件处理函数在n秒内只执行一次,并且是在触发操作结束时执行,若在n秒内再次触发则重新计算。用于下拉触底加载下一页、即时查询、scroll事件场景。

解决原理:对处理函数进行延时操作,若设定的延时到来之前再次触发事件,则清除上一次的延时操作定时器,重新定时。

// 等待wait后执行事件
function debounce(fn, wait) {
    let timer = null;
    return function() {
        if(timer) {
            clearTimeout(timer);
        }
        timer = setTimeout(() => {
            fn.apply(this, arguments)
        }, wait)
    }
}
    
// 立即执行事件,等待wait后再次执行事件
function debounce(fn, wait) {
     let timer = null;
     return function() {
         if(timer) {
             clearTimeout(timer);
         }
         let callNow = !timer;
         timer = setTimeout(() => {
             timer = null;
         }, wait)
         if(callNow) {
            fn.apply(this, arguments)
         }
     }
 }
     
// scroll事件
let timer;
window.onscroll = function () {
  if(timer){
	clearTimeout(timer)
  }
  timer = setTimeout(() => {
	//滚动条位置
	let scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
	console.log('滚动条位置:' + scrollTop);
	timer = null;
  },200)
}

节流:一定时间只调用一次 ,连续发生的事件在n秒内只执行一次,场景:提交表单,高频监听

function throttle(fn, delay) {
        let timer = null;
        return function() {
            const context = this,
                  args = arguments
            if(!timer) {
                timer = setTimeout(() => {
                    fn.apply(context, args);
                    timer = null
                }, delay);
            }
        }
    }
    function throttle1(fn, delay) {
        let curTime = Date.now();

        return function () {
            const context = this,
                  args = arguments,
                  nowTime = Date.now();

            if (nowTime - curTime >= delay) {
                curTime = Date.now();
                return fn.apply(context, args);
            }
        };
    }
	function throttle2(fn, ms) {
        let flag = false;
        
        return (...args) => {
            if (flag) {
                return;
            }
            flag = true;
            setTimeout(() => {
                fn(...args);
                flag = false;
            }, ms);
        };
    }

参考文献:【前端性能】高性能滚动 scroll 及页面渲染优化 - ChokCoco - 博客园

9. promise

9.1 promiseA+规范:Promises/A+ (promisesaplus.com)

  • Promise对象为异步编程提供统一接口,每个异步任务返回一个Promise对象,该对象有一个then方法,允许指定回调函数
  • 一个promise可能有三种状态:等待(pending)、已完成(resolved/fulfilled)、已拒绝(rejected);对象的状态不受外部影响,promise只能从pending转到fulfilled或者rejected,一旦状态改变就不会再变
  • 实例化promise对象需要传入函数,该函数包含resolve、reject两个函数作为参数,resolve和reject中可以传入参数在then回调函数中使用
  • promise必须提供一个then方法,then接收两个函数作为参数(可选参数);第一个参数是成功时的回调,在promise由"pending"转换到"resolved"时调用;另一个是失败时的回调,在promise由"pending"转换到"rejected"时调用;如果then接收的参数不是函数则发生透传
  • then方法必须返回一个promise对象,同一个promise的then可以链式调用,回调的执行顺序跟它们被定义时的顺序一致
  • catch相当于.then(null,reject),当then中没有传入reject时,错误会冒泡进入catch中,若传入了reject则被reject捕获不会进入catch
  • then中的回调函数中发生的错误只会在下一级的then中被捕获,不会影响该promise的状态
  • promise能够在then中的回调函数return出promise对象或其他值,也可以throw出错误对象,但如果没有return,将默认返回undefined,后面的then中的回调参数接收到的将是undefined

9.2 promise方法

静态方法:Promise.all()  Promise.any() Promise.allSettled() Promise.race()

实例方法:Promise.prototype.then()  Promise.prototype.catch()   Promise.prototype.finally()

9.3 手写promise:

参考文献:实现一个完美符合Promise/A+规范的Promise 

// Promise的基本用法
let promise1 = new Promise((resolve,reject) => 
    setTimeout(() => resolve('ok'), 1000))
promise1.then((val) => console.log(val))

// 串行执行三个promise,A、B和C
A.then(B).then(C).catch(...)
(async () => {await a(); await b(); await c();})()

// Promise手写
function myPromise(excutor) {
    // 1.执行结构
    let self = this;
    self.status = 'pending';
    self.value = null;
    self.reson = null;
    // 6.添加回调函数缓存数组
    self.onFulfilledCallbacks = [];
    self.onRejectedCallbacks = [];

    // 4.判断状态,做相应处理
    function resolve(value) {
        self.value = value;
        self.status = 'fulFilled'
        // 8.状态改变,执行回调函数
        self.onFulfilledCallbacks.forEach(item => item(value))
    }
    function reject(reson) {
        self.reson = reson;
        self.status = 'rejected';
        self.onRejectedCallbacks.forEach(item => item(reason))
    }
    // 3. 执行一遍
    try {
        excutor(resolve, reject)
    }catch(err) {
        reject(err)
    }
}

 // 2.添加then
myPromise.prototype.then = function(onFulfilled, onRejected) {
     // 5. 判断then中的参数
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : (data) => resolve(data);
    onRejected = typeof onRejected === 'function' ? onRejected : (err) => {throw err};
    let self = this;
    // 7.添加回调函数到缓存数组解决异步
    if(self.status === 'pending') {
        self.onFulfilledCallbacks.push(onFulfilled);
    	self.onRejectedCallbacks.push(onRejected);
    }
}

// 9.添加catch
myPromise.prototype.catch = function(fn) {
    return this.then(null, fn)
}

9.4 ajax封装promise

var myNewAjax = function(url){
    return new Promise((resolve,reject) =>{
        var xhr = new XMLHttpRequest();
        xhr.open('get',url);
    	xhr.send();
    	xhr.onreadystatechange = function(){
            if(xhr.status == 200 && xhr.readyState == 4{
            	var json = JSON.parse(xhr.responseText);
            	resolve(json)
        	}else if(xhr.readyState == 4 && xhr.status != 200){
            	reject('error');
        	}
		}
	})
}

10.  async

async表示这是一个async异步函数,await只能用在这个函数里面

await表示等待异步操作的返回结果,再继续执行,await后一般是一个promise对象

如果async函数返回的是一个同步的值,将等同于return Promise.resolve(value)

(async () => {await new promise();})()

let timer = async function timer(){
    return new Promise((resolve,reject)=>{
        setTimeout(() => resolve('500'),500)
    })
}
timer()
    .then(result=> console.log(result)) // 500
    .catch(err => console.log(err.message));

//返回一个同步的值
let sayHi = async function sayHi(){
    let hi = await 'helloworld';
    return hi;//等同于return Promise.resolve(hi);
}
sayHi().then(result=>console.log(result));

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值