call,apply,bind详解
为什么要改变this指向?
我们知道bind,call,apply的作用都是用来改变this指向的,那为什么要改变this指向呢?请看下面的例子:
var name="lucy";
let obj={
name:"martin",
say:function () {
console.log(this.name);
}
};
obj.say(); //martin,this指向obj对象
setTimeout(obj.say,0); //lucy,this指向window对象
可以观察到,正常情况下 say 方法中的 this 是指向调用它的 obj 对象的,而定时器 setTimeout 中的 say 方法中的 this 是指向window对象的(在浏览器中),这是因为 say 方法在定时器中是作为回调函数来执行的,因此回到主栈执行时是在全局执行上下文的环境中执行的,但我们需要的是 say 方法中 this 指向obj对象,因此我们需要修改 this 的指向。
apply方法
apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入,且当第一个参数为null、undefined的时候,默认指向window(在浏览器中),使用apply方法改变this指向后原函数会立即执行,且此方法只是临时改变thi指向一次。
日常用法:改变this指向
示例:
回调函数绑定this指向:
var name="martin";
var obj={
name:"lucy",
say:function(year,place){
console.log(this.name+" is "+year+" born from "+place);
}
};
var say=obj.say;
setTimeout(function(){
say.apply(obj,["1996","China"])
} ,0); //lucy is 1996 born from China,this改变指向了obj
say("1996","China") //martin is 1996 born from China,this指向window,说明apply只是临时改变一次this指向
小技巧:改变参数传入方式
示例:
求数组中的最大值:
var arr=[1,10,5,8,3];
console.log(Math.max.apply(null, arr)); //10
其中Math.max函数的参数是以参数列表,如:Math.max(1,10,5,8,3)的形式传入的,因此我们没法直接把数组当做参数,但是apply方法可以将数组参数转换成列表参数传入,从而直接求数组的最大值。
call方法
call方法的第一个参数也是this的指向,后面传入的是一个参数列表(注意和apply传参的区别)。当一个参数为null或undefined的时候,表示指向window(在浏览器中),和apply一样,call也只是临时改变一次this指向,并立即执行。
示例:
var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); //10
采纳以参数列表的形式传入,而apply以参数数组的形式传入。
bind方法
bind方法和call很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入,call则必须一次性传入所有参数),但是它改变this指向后不会立即执行,而是返回一个永久改变this指向的函数。
示例:
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分两次传参
可以看出,bind方法可以分多次传参,最后函数运行时会把所有参数连接起来一起放入函数运行。
实现bind方法(面试题):
简易版
Function.prototype.bind=function () {
var _this=this;
var context=arguments[0];
var arg=[].slice.call(arguments,1);
return function(){
arg=[].concat.apply(arg,arguments);
_this.apply(context,arg);
}
};
完美版
//实现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 fBound === true时,说明返回的fBound被当做new的构造函数调用
return fToBind.apply(this instanceof fBound
? this
: oThis,
// 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的
aArgs.concat(Array.prototype.slice.call(arguments)));
};
// 维护原型关系
if (this.prototype) {
// 当执行Function.prototype.bind()时, this为Function.prototype
// this.prototype(即Function.prototype.prototype)为undefined
fNOP.prototype = this.prototype;
}
// 下行的代码使fBound.prototype是fNOP的实例,因此
// 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例
fBound.prototype = new fNOP();
return fBound;
};
var arr=[1,11,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3]);
console.log(max(arr[4])); //12
apply,call,bind三者的区别
- 三者都可以改变函数的this对象指向。
- 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefined或null,则默认指向全局window。
- 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入。
- bind 是返回绑定this之后的函数,便于稍后调用;apply 、call 则是立即执行 。
call,apply,bind详解的更多相关文章
- call Apply bind详解
call方法: 语法:call(thisObj,'',''........) 定义:调用一个对象的一个方法,以另一个对象替换当前对象 说明:call方法可以用来代替另一个对象调用一个方法.call方法 ...
- 011-Scala中的apply实战详解
011-Scala中的apply实战详解 object中的apply方法 class中的apply方法 使用方法 apply方法可以应用在类或者Object对象中 class类 必须要创建实例化的类对 ...
- Js apply 方法 详解
Js apply方法详解 我在一开始看到JavaScript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- Js apply()使用详解
Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- angularJS中$apply()方法详解
这篇文章主要介绍了angularJS中$apply()方法详解,需要的朋友可以参考下 对于一个在前端属于纯新手的我来说,Javascript都还是一知半解,要想直接上手angular JS,遇到的 ...
- Js apply方法详解,及其apply()方法的妙用
Js apply方法详解 我在一开始看到javascript的函数apply和call时,非常的模糊,看也看不懂,最近在网上看到一些文章对apply方法和call的一些示例,总算是看的有点眉目了,在这 ...
- 原生JS:Function对象(apply、call、bind)详解
Function对象(apply.call.bind) 原创文章,转摘请注明出处:苏福:http://www.cnblogs.com/susufufu/p/5850180.html 本文参考MDN做的 ...
- javascript中的apply,call,bind详解
apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. Jav ...
- call,apply和bind详解
一.call和apply call和apply其实是同一个东西,区别只有参数不同,call是apply的语法糖,所以就放在一起说了,这两个方法都是定义在函数对象的原型上的(Function.proto ...
随机推荐
- 那些年,我们见过的Java服务端乱象
导读 查尔斯·狄更斯在<双城记>中写道:“这是一个最好的时代,也是一个最坏的时代.”移动互联网的快速发展,出现了许多新机遇,很多创业者伺机而动:随着行业竞争加剧,互联网红利逐渐消失,很多创 ...
- JavaScript远程调用
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- bzoj 3895 取石子——博弈论
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3895 看题解:https://blog.csdn.net/popoqqq/article/d ...
- 学习es6
#第一节 初始化项目 npm init -y 安装babel-cli npm install -g babel-cli npm install --save-dev babel-preset-es20 ...
- Leetcode888.Fair Candy Swap公平的糖果交换
爱丽丝和鲍勃有不同大小的糖果棒:A[i] 是爱丽丝拥有的第 i 块糖的大小,B[j] 是鲍勃拥有的第 j 块糖的大小. 因为他们是朋友,所以他们想交换一个糖果棒,这样交换后,他们都有相同的糖果总量.( ...
- LintCode刷题笔记-- Update Bits
标签: 位运算 描述: Given two 32-bit numbers, N and M, and two bit positions, i and j. Write a method to set ...
- PAT天梯赛L1-002 打印漏斗
题目链接:点击打开链接 本题要求你写个程序把给定的符号打印成沙漏的形状.例如给定17个"*",要求按下列格式打印 ***** *** * *** ***** 所谓"沙漏形 ...
- day39-Spring 01-上次课内容回顾
- Kubernetes Ingress日志分析入门
本文主要介绍如何基于日志服务构建Kubernetes Ingress日志分析平台,并提供一些简单的动手实验方便大家快速了解日志服务相关功能. 部署Ingress日志方案 登录容器服务管理控制台. 将上 ...
- Linux下的python安装
centos7安装python3 以及tab补全功能 1.安装python3 1.1下载python源码包 网址:https://www.python.org/downloads/release/ ...