学习Function.prototype.bind、call与apply时,看到一篇博客,学到一些内容,但由于博客时间太久,根据官方文档对内容进行一些修正;下文为修正过内容

前言

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

    functionParent() {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对象。所以我们只能换种思路解决了

思路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.prototype.bind) {
Function.prototype.bind = function(oThis) {
if (typeof this !== 'function') {
// closest thing possible to the ECMAScript 5
// internal IsCallable function
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
} var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function() {},
fBound = function() {
// this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fNOP
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
}; // 维护原型关系
if (this.prototype) {
// Function.prototype doesn't have a prototype property
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP(); return fBound;
};
}

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

    function(el, type, fn) {
el.attachEvent('on' + type, fn.bind(el, event));
}

Function.prototype.bind、call与apply的更多相关文章

  1. Function.prototype.bind、call与apply方法简介

    前言 前段时间面试遇见一题,题目内容大概是 function Parent() { this.prop = 'parent'; } Parent.prototype.get = function() ...

  2. 一起Polyfill系列:Function.prototype.bind的四个阶段

    昨天边参考es5-shim边自己实现Function.prototype.bind,发现有不少以前忽视了的地方,这里就作为一个小总结吧. 一.Function.prototype.bind的作用 其实 ...

  3. Function.prototype.bind接口浅析

    本文大部分内容翻译自 MDN内容, 翻译内容经过自己的理解. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Glo ...

  4. JavaScript 函数绑定 Function.prototype.bind

    ECMAScript Edition5 IE9+支持原生,作用为将一个对象的方法绑定到另一个对象上执行. Function.prototype.bind = Function.prototype.bi ...

  5. Function.prototype.bind

    解析Function.prototype.bind 简介 对于一个给定的函数,创造一个绑定对象的新函数,这个函数和之前的函数功能一样,this值是它的第一个参数,其它参数,作为新的函数的给定参数. b ...

  6. 解析Function.prototype.bind

    简介 对于一个给定的函数,创造一个绑定对象的新函数,这个函数和之前的函数功能一样,this值是它的第一个参数,其它参数,作为新的函数的给定参数. bind的作用 bind最直接的作用就是改变this的 ...

  7. javascript Function.prototype.bind

    语法: fn.bind(obj,arg1,arg2,arg3...) bind是es5新增的方法,顾名思义,它的作用是将函数绑定到某个对象上,就像是某个对象调用方法一样.其本质还是改变了该函数的上下文 ...

  8. 理解javascript中的Function.prototype.bind

    在初学Javascript时,我们也许不需要担心函数绑定的问题,但是当我们需要在另一个函数中保持上下文对象this时,就会遇到相应的问题了,我见过很多人处理这种问题都是先将this赋值给一个变量(比如 ...

  9. 浅析 JavaScript 中的 Function.prototype.bind() 方法

    Function.prototype.bind()方法 bind() 方法的主要作用就是将函数绑定至某个对象,bind() 方法会创建一个函数,函数体内this对象的值会被绑定到传入bind() 函数 ...

随机推荐

  1. Jenkins_创建任务以及定时启动(2)

    一.创建任务 1.点击New Item 2.输入用户,单击Freestyle project,点击OK 3.填写构建步骤,因为是安装在linux上的,所以我们选择Execute shell,随意输入一 ...

  2. centos7 安装locate

    使用locate my.cnf命令可以列出所有的my.cnf文件 yum  -y install mlocate 原因是安装完后没有更新库 更新库:updatedb

  3. MySQL 开启和关闭远程访问

    MySQL 开启和关闭远程访问权限 一.开启MySQL/MariaDB的远程访问权限 [root@localhost ~]# mysql -u root -p MariaDB [(none)]> ...

  4. Python 国内镜像源

    让 python pip 使用国内镜像源 国内镜像源: 清华:https://pypi.tuna.tsinghua.edu.cn/simple 阿里云:http://mirrors.aliyun.co ...

  5. Echart可视化学习(十一)

    文档的源代码地址,需要的下载就可以了(访问密码:7567) https://url56.ctfile.com/f/34653256-527823386-04154f 官网找到类似实例, 适当分析,并且 ...

  6. vue3.0+vite+ts项目搭建-axios封装(六)

    封装方式一 import axios from 'axios' import qs from 'qs' import { Toast } from 'vant' import Lockr from ' ...

  7. python+selenium 元素定位--iframe

    1. 一般webdriver要操作页面元素需要在Top Window的状态下,如下: 2.当浏览器显示iframe时,用正常的元素定位是没有效果的,需要将页面装换到iframe下再对页面元素进行操作 ...

  8. 【Java】成员变量赋值执行顺序

    程序中成员变量赋值的执行顺序

  9. tomcat容器启动失败疑难问题解决方案

    严重: 子容器启动失败java.util.concurrent.ExecutionException: org.apache.catalina.LifecycleException: 初始化组件[or ...

  10. 【小测试】使用腾讯云上的群集版redis

    具体的文档请见:https://cloud.tencent.com/document/product/239/3205 群集版本相当于很多个redis进程构成一个群集,最大支持128个分片(猜测分片就 ...