最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 面试 |call, apply, bind的模拟实现和经典面试题

    正文概述 掘金(LinYIYI)   2021-03-31   642

    思维导图

    面试 |call, apply, bind的模拟实现和经典面试题

    call,apply,bind 都可以改变 this 的指向

    一、call 格式 [function].call([this], [param]...),一句话概括:call() 将函数的 this 指定到 call() 的第一个参数值和剩余参数指定的情况下调用某个函数或方法。

    思考

    1. 热身题1

    function fn(a, b) {
        console.log(this, a, b)
    }
    
    var obj = {
        name: '林一一'
    }
    
    fn.call(obj, 20, 23)   // {name: "林一一"} 20 23
    
    fn.call(20, 23) // Number {20} 23 undefined
    
    fn.call()   //Window {0: global, window: …} undefined undefined     | 严格模式下为 undefined
    
    fn.call(null)   //Window {0: global, window: …} undefined undefined       | 严格模式下为 null
    
    fn.call(undefined)  //Window {0: global, window: …} undefined undefined     | 严格模式下为 undefined
    

    2. 热身题 2

    var obj1 = {
        a: 10,
        fn: function(x) {
            console.log(this.a + x)
        }
    }
    
    var obj2 = {
        a : 20,
        fn: function(x) {
            console.log(this.a - x)
        }
    }
    
    obj1.fn.call(obj2, 20) //40
    

    二、apply 和 call 基本一致

    两者唯一不同的是:apply 的除了一个this指向的参数外,第二个参数是数组[arg1, arg2...],call的第二参数是列表(arg1, arg2...)

    var name = '二二'
    var obj = {
        name: '林一一',
        fn: function() {
            return `${this.name + [...arguments]}`
        }
    }
    obj.fn.apply(window, [12, 23, 34, 56])    // "二二12,23,34,56"
    

    面试题

    1. 模拟实现内置的 call(),apply()方法。

    • call 的模拟实现
    Function.prototype.myCall = function (context, ...args){
        context = context || window
        // 这里的 this 是指向 fn 的,通过 this 就可以获取 fn,context 是我们的 obj,可以直接给 obj 添加一个函数属性
        context.fn = this
        delete context.fn(...args)
        return
    }
    
    var name = '二二'
    var obj = {
        name: '林一一',
    }
    
    function fn() {
        console.log(this.name, ...arguments)
    }
    
    fn.myCall(null)
    fn.myCall(obj, 12, 23, 45, 567)
    
    • apply 的模拟实现
    Function.prototype.myApply = function (context, args){
        context = context || window
        context.fn = this
        delete context.fn(args)
        return
    }
    

    2. call 和 apply 区别

    var name = '二二'
    var obj = {
        name: '林一一'
    }
    
    function fn(){
        console.log(this.name, ...arguments)
    }
    
    fn.apply(obj, [12, 34, 45, 56]) //fn(12, 23, 45, 56) 林一一   12 34 45 56
    

    三、bind

    • 返回一个新函数,这个新函数执行时的 this 才指定到 bind 的第一个参数
    • bind 的剩余参数,传递给新的函数
    • 返回后的新函数是自我调用的

    小思考

    1. 上面说的这个新函数是啥?

    一个小栗子

    var name = '二二'
    var obj = {
        name: '林一一'
    }
    
    function fn(){
        return `${this.name} ` + [...arguments]
    }
    
    let f = fn.bind(obj, 12, 23, 45, 67, 90)
    f() // "林一一 12,23,45,67,90"
    

    2. bind 是怎么实现拷贝 fn 的?

    面试题

    1. bind() 和 call()、apply() 的区别

    2. 模拟实现内置的 bind() 方法。

    下面的代码来自 JavaScript深入之bind的模拟实现

    Function.prototype.bind2 = function (context) {
    
        if (typeof this !== "function") {
          throw new Error("Function.prototype.bind - what is trying to be bound is not callable");
        }
    
        var self = this;
        var args = Array.prototype.slice.call(arguments, 1);
    
        var fNOP = function () {};
    
        var fBound = function () {
            var bindArgs = Array.prototype.slice.call(arguments);
            return self.apply(this instanceof fNOP ? this : context, args.concat(bindArgs));
        }
    
        fNOP.prototype = this.prototype;
        fBound.prototype = new fNOP();
        return fBound;
    }
    

    四、思考题

    1. 求数组中的最大值和最小值

    • let arr = [12, 45, 65, 3, 23, 11, 76, 8, 9, 56, 70]
      let max = Math.max(...arr)  // 76
      let min = Math.min(...arr)  // 3
      
    • let arr = [12, 45, 65, 3, 23, 11, 76, 8, 9, 56, 70]
      let list = arr.sort(function(a, b) {
          return b - a
      })
      let max = list[0]   // 76
      let min = list[list.length - 1] // 3
      
    • let arr = [12, 45, 65, 3, 23, 11, 76, 8, 9, 56, 70]
      let max = Math.max.apply(null, arr) // 76
      let min = Math.max.apply(null, arr) // 3
      

    2. 如何判断一个数组

    let arr = []
    Object.prototype.toString.call(arr)
    

    3.Object.prototype.toString.call() 为什么可以用来判断类型

    Object.prototype.toString.call('str')   // "[object String]"
    Object.prototype.toString.call(123)   // "[object Number]"
    Object.prototype.toString.call({})      //  "[object Object]"
    Object.prototype.toString.call([])      //  "[object Array]"
    
    Object.prototype.toString.apply({})      //  "[object Object]"
    Object.prototype.toString.apply([])      //  "[object Array]"
    
    var f = Object.prototype.toString.bind({})
    f()     //  "[object Object]"
    var fn = Object.prototype.toString.bind([])
    fn()   //  "[object Array]"
    

    4.使用 call() 实现将类数组转化成数组

    let array = [12, 23, 45, 65, 32]
    function fn(array){
        var args = [].slice.call(arguments)
        return args[0]
    }
    fn(array)   // [12, 23, 45, 65, 32]
    

    参考

    JavaScript深入之call和apply的模拟实现

    JavaScript深入之bind的模拟实现

    MDN bind

    结束


    起源地下载网 » 面试 |call, apply, bind的模拟实现和经典面试题

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元