zoukankan      html  css  js  c++  java
  • Function.prototype.bind、call与apply方法简介

    前言

    前段时间面试遇见一题,题目内容大概是

    function Parent() {
        this.prop = 'parent';
    }
    
    Parent.prototype.get = function() {
        alert(this.prop);
    };
    
    Parent.prototype.show = function() {
        setTimeout(this.get, 100);
    };
    
    var child = new Parent();
    child.show(); // ?

    分析

    上述题目考察的是this的指向性这个经典问题。
    众所周知,setTimeout是window对象的一个属性,主要起到延迟给定函数执行的作用。setTimeout(fn, delay),因此this.get的这个this指向的是window对象,但是我们并没用在window对象上定义相应的get函数,所以会报错,而不是调用构造函数Parent的原型中的get方法。

    怎么改?

    经过上面的分析,我们知道setTimeout(this.get, 100)会报错,但是如果我们想正常调用并且alert出正确的值,应该怎么改?
    改动的原理很明确,就是将setTimeout中的this指向Parent.prototype,但是单纯的将this.get改成Parent.prototype.get仍然没有alert出真正的parent,而是undefined,原理仍然是原型中的get方法在通过实例对象child调用时内部的this仍然指向window对象。所以我们只能换种思路解决了

    ps: 这个当时卡壳了,没答上来,汗。。。

    思路1

    Parent.prototype.show = function (){
        var that = this;
        setTimeout(this.get.call(that), 100);
    }

    这种方法在很多框架中经常使用,即先存储this默认指向的作用域,然后改变函数内部绑定的作用域来实现。ps: 不通过that存储,直接传递this也可

    思路2

    ES5中对函数方面唯一扩展是新增了一个bind函数,用于劫持函数作用域,并预先添加更多参数,然后返回绑定了新作用域的函数。而现在我们也可以使用它,其实这个思路在MDN上有相应的介绍使用,哎,只怪自己的年少无知。。。

    Parent.prototype.show = function() {
        setTimeout(this.get.bind(this), 100);
    };

    bind/call/apply

    三者都是用于绑定函数作用域,区别如下:

    • call 是obj.method()到method(obj)的变换,返回函数调用结果,所需参数依次用逗号分割添加至obj尾部。
    • apply 功能同call,区别是传递参数的方式不是call的那种参数列表形式,而是以数组或类数组形式传递。
    • bind 返回绑定作用域后的一个新函数,不会执行函数

    我们可以通过apply方法实现bind函数:

    if(!function() {}.bind) {
        Function.prototype.bind = function(context) {
            if (arguments.length < 2 && context == void 0)
                return this;
            var _self = this,
                args = [].slice.call(arguments, 1);
            return function() {
                _self.apply(context, args.concat.apply(args, arguments));
            }
        }
    }

    另外,我们可以利用bind修复IE事件绑定attachEvent回调中的this问题,它总是指向window对象,而标准浏览器的addEventListener中的this则为其调用对象。

    function(el, type, fn) {
        el.attachEvent('on' + type, fn.bind(el, event));
    }
  • 相关阅读:
    new Employee()) ->setName('Tom') ->setSurname('Smith') ->setSalary('100');
    空指针异常 自动拆箱 防止 NPE,是程序员的基本修养 本手册明确防止 NPE 是调用者的责任。
    回放用户细节操作 主动抓取用户的日志分析用户行为
    API 设计指南 将 RPC API(基于套接字)与 REST API(基于 HTTP)的设计融合起来
    100-continue
    人们就可以专注于”你在说什么”, 而不是”你在怎么说”.
    http://sideeffect.kr/popularconvention#javascript
    IntelliJ Idea设置默认换行符 Idea
    Fixed-Length Frames 谈谈网络编程中应用层(基于TCP/UDP)的协议设计
    h256
  • 原文地址:https://www.cnblogs.com/qingguo/p/5686286.html
Copyright © 2011-2022 走看看