Function.prototype.bind、call与apply
学习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的更多相关文章
- Function.prototype.bind、call与apply方法简介
前言 前段时间面试遇见一题,题目内容大概是 function Parent() { this.prop = 'parent'; } Parent.prototype.get = function() ...
- 一起Polyfill系列:Function.prototype.bind的四个阶段
昨天边参考es5-shim边自己实现Function.prototype.bind,发现有不少以前忽视了的地方,这里就作为一个小总结吧. 一.Function.prototype.bind的作用 其实 ...
- Function.prototype.bind接口浅析
本文大部分内容翻译自 MDN内容, 翻译内容经过自己的理解. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Glo ...
- JavaScript 函数绑定 Function.prototype.bind
ECMAScript Edition5 IE9+支持原生,作用为将一个对象的方法绑定到另一个对象上执行. Function.prototype.bind = Function.prototype.bi ...
- Function.prototype.bind
解析Function.prototype.bind 简介 对于一个给定的函数,创造一个绑定对象的新函数,这个函数和之前的函数功能一样,this值是它的第一个参数,其它参数,作为新的函数的给定参数. b ...
- 解析Function.prototype.bind
简介 对于一个给定的函数,创造一个绑定对象的新函数,这个函数和之前的函数功能一样,this值是它的第一个参数,其它参数,作为新的函数的给定参数. bind的作用 bind最直接的作用就是改变this的 ...
- javascript Function.prototype.bind
语法: fn.bind(obj,arg1,arg2,arg3...) bind是es5新增的方法,顾名思义,它的作用是将函数绑定到某个对象上,就像是某个对象调用方法一样.其本质还是改变了该函数的上下文 ...
- 理解javascript中的Function.prototype.bind
在初学Javascript时,我们也许不需要担心函数绑定的问题,但是当我们需要在另一个函数中保持上下文对象this时,就会遇到相应的问题了,我见过很多人处理这种问题都是先将this赋值给一个变量(比如 ...
- 浅析 JavaScript 中的 Function.prototype.bind() 方法
Function.prototype.bind()方法 bind() 方法的主要作用就是将函数绑定至某个对象,bind() 方法会创建一个函数,函数体内this对象的值会被绑定到传入bind() 函数 ...
随机推荐
- Java初学者作业——编写 Java 程序,用户输入 3 个操作数,分别求出最大值、最小值和平均值。
返回本章节 返回作业目录 需求说明: 编写 Java 程序,用户输入 3 个操作数,分别求出最大值.最小值和平均值. 实现思路: 定义 Java 类,定义 3 个方法,用来求 3 个数字的最大值.最小 ...
- 编写Java程序,使用ThreadLocal类,项目中创建账户类 Account,类中包括账户名称name、 ThreadLocal 类的引用变量amount,表示存款
查看本章节 查看作业目录 需求说明: 某用户共有两张银行卡,账户名称相同,但卡号和余额不同.模拟用户使用这两张银行卡进行消费的过程,并打印出消费明细 实现思路: 项目中创建账户类 Account,类中 ...
- x86-2-保护模式
x86-2-保护模式 操作系统负责计算机上的所有软件和硬件的管理,它可以百分百操作计算机的所有内容.但是,操作系统上编写的用户程序却应当有所限制,只允许用户程序访问属于自己程序的内容,不然整个生态就很 ...
- AWS 15年(2):云原生兴起
AWS创立云计算15年来,没有一个行业不跟云计算相关,没有任何一个颠覆性创新缺少云计算的参与,云已经是不可逆的滚滚洪流. AWS这15年,是云原生服务从无到有再到基本成熟的15年,是云原生应用兴起的1 ...
- nginx配置图片路径
首先, 在linux下创建你存放资源的目录,例如:/data/images:用于存放图片. 下一步,打开default.conf配置文件找到server块下的location添加如下 location ...
- CentOS7查询端口占用,清除端口占用的程序,开放端口,打开防火墙
1.根据端口号得到其占用的进程的详细信息 netstat -tlnp|grep 80tcp 0 0 192.168.33.10:80 0.0.0.0:* ...
- Linux上天之路(五)之Linux基本命令
1. Linux命令格式 命令 命令选项 学会看语法: {必选项}[可选项] 举例 ls -a /tmp 等价 ls –all /tmp ls 命令 -a 命令选项 简写使用- 全写-- /tmp 参 ...
- Spark-local本地环境搭建
注:图片如果损坏,点击文章链接:https://www.toutiao.com/i6815385772254822919/ 承接上一个文档<Spark源码编译> 解压spark编译好的压缩 ...
- vue实现引用less,sass全局变量
1.npm install sass-resources-loader --save-dev: 2.build/utils.js中,修改 function resolveResource(name) ...
- vue-cli axios封装(element-ui)
1.http.js /** * * http配置 */ import axios from 'axios'import { Loading, Message } from 'element-ui' / ...