this,call,apply,bind浅析
在JS中,this指向是一个难点,在本文中讲解几种常见的this指向问题,并介绍一下call,apply,bind这三个函数的用法。
一、常见的this指向情况
首先要明白一点就是,函数里面才会有this,而this指向是由函数执行的方式来决定的,并且this指向的一定是对象,常见的有三种情况:
- 函数名(),即函数名加括号自执行,该函数里面的this指向window对象;
- 对象.方法(),即对象点属性方法加括号执行,此方法内的this指向该对象;
- 无论什么形式的事件函数,函数内部的this指向触发事件的对象。
下面我们来看几个例子:
案例1:
var oBox = document.getElementById('box');
function a() {
console.log( this );
}
a();
document.onclick = a;
//oBox.onclick = a;
打开控制台,会看到打印了一个window,这是第6行a(),a函数自执行时,函数内部的this指向window对象。然后,我们点击一下页面,触发了document的onclick事件,此时控制台会再打印一个document,只是因为事件函数内部的this指向触发该事件的对象。同理,如果我们把第7行注释,第8行取消注释,代码功能换成给页面上一个id为‘box’的标签对象注册一个点击事件,那么当我们在页面上点击这个标签的时候,控制台会给我们打印出这个标签(如下图)。

案例二:
var obj = {
name:'Person',
fn:function(){
console.log(this);
}
}
obj.fn();
这个案例里,fn是对象obj的一个方法,当我们用obj.fn()执行的时候,fn里的this指向obj,我们会看到控制台打印的效果如下:

案例三:
var a = function () {
console.log( this );
};
function x() {
a();
}
x();
这个案例里的this指向的是window,即我们开篇说的第一种情况。这里可能有一个误导的地方就是,有人会觉得a在x中运行,this会指向x,其实我们只要再认真读一下我们之前说过的两点就会明白了,一点是this指向一定是一个对象,这里x不是对象,另一点就是函数名加括号自执行,this指向window,不管这个函数在放在哪里执行的,哪怕是放在一个对象里面,只要它是函数名加括号自执行的方式,那么它里面的this指向一定是window。
案例四:
function x() {
function a() {
console.log(this);
}
a();
}
x();
这里的this也是指向window,吃透了案例三,再看案例四就觉得简单了。
案例五:
var oBox = document.getElementById("box");
oBox.a = function () {
console.log(this);
};
oBox.a();
(oBox.a)();
document.onclick = oBox.a;
这个案例里,第7行和第8行打印的this为id是box的标签,当我们点击一下页面后,会打印document,因为无论什么形式的事件函数,里面的this都会指向触发该事件的对象。以下是控制台的打印结果:

this剖析:this本身就是一个对象,跟其他数据类型一样,JS也会在内存中给它分配一个地址,只是是动态的,不是固定的,它的变化是根据不同执行环境来动态分配的。而this是什么时候产生呢,就是this指向的对象是什么时候产生,this就是什么时候产生,我们前面总结的第一种情况,函数名加括号自执行,实际上是window.函数名()执行的,所以this会指向window,那么实际上和第二种情况对象.函数名()执行方式是一样的。
二、改变this指向
在我们的实际运用中,有时候我们需要改变this的指向,JS给我们提供了三个改变this执行的方法:call,apply和bind,让我们先来看看它们的用法和不同之处。
- call:
在函数执行阶段使用,可以改变this指向;
call的第一个参数代表函数的this指向;
原函数的第一个形参对应call的第二位实参,第二个形参对应call的第三位实参,以此类推。 - apply:
在函数执行阶段使用,可以改变this指向;
apply的第一个参数代表函数的this指向;
apply的第二个参数是个数组,数组第一位对应原函数第一个形参,以此类推。 - bind:(不支持IE8及以下)
并不会立刻帮助函数去自执行,当函数执行的时候去改变this指向;
参数形式和call一样。
它们的用法是:函数名.call(arg1,arg2,agr3......)、函数名.apply(arg1,[arg2,arg3......])、函数.bind(arg1,arg2,arg3......),主要的区别在于call和apply会让函数立即自执行,而bind不会让函数自执行;而call和apply的区别在于传参的不同,apply的第二个参数是一个数组。下面我们来看几个实际的例子:
案例六:
function a(x,y) {
console.log(x+y);
console.log(this);
}
a(1,2);
a.call(document,5,5);
a.apply(oBox,[5,1]);
这个案例里,第6行a函数自执行了一次,第7行用call来执行a函数,改变this指向为document,而第8行用apply来执行函数a,改变其this指向为oBox对象,并且这里传的第二个参数用了一个数组。最终的打印结果如下:

案例七:
function a(x) {
console.log(x);
console.log(this);
}
a.call(null,1);
a.apply(undefined,[2]);
当我们给call、apply和bind的第一个参数传null或者undefined时,this指向window,有时候我们只需要利用call、apply、bind传参而不需要改变this指向时,我们会这样用。下面我们一起来看打印的结果:

案例八:
var oBox = document.getElementById("box");
oBox.x = function () {
console.log(this);
};
oBox.x();
oBox.x.call(document);
对象的方法依然可以通过call、apply和bind改变this指向。效果如下:

下面我们来看看bind,它的用法和call是类似的,不同在于它不会立即执行函数,而是在函数被动执行的时候再去改变this指向,我们看下面的例子:
案例九:
var oBox = document.getElementById("box");
var oWrap = document.getElementById("wrap");
oBox.onclick = eFn.bind(oBox,200,150);
oWrap.onclick = eFn.bind(oWrap,150,200);
function eFn(x,y) {
this.style.width = x+"px";
this.style.height = y+"px";
}
页面上有两个div标签,一个id为box,一个id为wrap,我们希望实现一个功能,就是点击它们的时候,它们分别按照不同的值去改变宽高,因为功能一致,所以我们把它们的点击事件函数进行封装,在封装函数中改变当前点击对象的宽高,因为点击事件是被动触发的,所以此时我们会用到bind,通过bind巧妙传递参数并且改变this指向,达到我们想要实现的功能,这个案例是bind的一个经典运用。
值得一提的是,apply和bind除了改变this指向的功能,在传参方式上也给我们提供了一些好的解决办法,bind可以在传参的同时不主动执行这个函数,给我们在写事件函数传参和定时器函数传参时提供了方便,而apply用数组传参的方式也给我们提供了新的便利,比如下面的例子:
案例10:
我们需要找出一个数字数组中的最大值,我们知道Math有个max方法是找最大值的,但是max接收的参数是分开的一个个的数字,而不是数组,所以找出数组的最大值,通常我们的做法是这样的:
var arr = [3,16,5,6,9,12,32,21];
var max =arr[0];
for (var i = 1; i < arr.length; i++) {
if(arr[i]>max)
max = arr[i];
}
console.log(max);
但是apply给我们提供了一个更好的解决方式,如下:
var arr = [3,16,5,6,9,12,32,21];
var max = Math.max.apply(null,arr);
console.log(max);
以上是本文的全部内容,感谢阅读!
this,call,apply,bind浅析的更多相关文章
- call,apply,bind的用法
关于call,apply,bind这三个函数的用法,是学习javascript这门语言无法越过的知识点.下边我就来好好总结一下它们三者各自的用法,及常见的应用场景. 首先看call这个函数,可以理解成 ...
- JavaScript中call,apply,bind方法的总结。
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...
- call(),apply(),bind()与回调
1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...
- JS 的 call apply bind 方法
js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context) call call([thisObj[,arg1[, arg2[, [,.argN]]]] ...
- javascript-this,call,apply,bind简述2
上节我们一起研究了this这个小兄弟,得出一个结论,this指向调用this所在函数(或作用域)的那个对象或作用域.不太理解的朋友可以看看上节的内容,这次我们主要探讨一下call(),apply(), ...
- javascript-this,call,apply,bind简述1
最近在系统的学习面向对象方面的知识,遇到的最大拦路虎就数this的指向,call,apply,bind函数的使用,单独抽出一天时间把这几个烦人的家伙搞定,去学习更深入的内容. 首先介绍一下this的一 ...
- call,apply,bind方法的总结
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...
- JavaScript中call,apply,bind方法的总结
原文链接:http://www.cnblogs.com/pssp/p/5215621.html why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之 ...
- call, apply,bind 方法解析
call(), apply(),bind() 三者皆为Function的方法 call(),apply()的作用是调用方法,并改变函数运行时的context(作用上下文) bind() 的作用是引用方 ...
- JS中call,apply,bind方法的总结
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user: "小马扎", fn: ...
随机推荐
- 「CQOI2007」「BZOJ1260」涂色paint (区间dp
1260: [CQOI2007]涂色paint Time Limit: 30 Sec Memory Limit: 64 MBSubmit: 2057 Solved: 1267[Submit][St ...
- [WC 2006] 水管局长
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=2594 [算法] 首先离线 , 将删边操作转化为倒序加边 假设我们已经维护出了一棵最小 ...
- RTP Payload Format for Transport of MPEG-4 Elementary Streams over http
1.SDP (1)Http Request GET /getSdpForUrl?HttpUrl=nphMpeg4/g726-640x480 HTTP/1.0/r/n Host: 58.63.71.90 ...
- 五、hibernate在myeclipse中生成实体和映射
- Hearthstone
题意: 有$n$个无中生有,有$m$个不同的杀,第$i$个杀掉$X_i$滴血,敌人血量$P$,求问第一回合就将敌人杀死的概率是多少. 解法: 二进制枚举$A$类,$B$类卡的顺序,这样就确定了取了几个 ...
- Asset Catalog Help (七)---Customizing Image Sets for Size Classes
Customizing Image Sets for Size Classes Add images to a set that are customized for display in diffe ...
- 2014-9-9 NOIP模拟赛
东方幻想乡系列模拟赛Stage 1命题 Nettle审题 Barty ccy1991911 FlanS39 Wagner T2 高精除高精,从来没写过,不知道怎么写,我就用大数减小数ans次,果断超时 ...
- 初学Django框架知识
首先了解什么事HTTP协议; 1.浏览器往服务器发的 请求(request): 请求消息的格式: 请求方法 路径 HTTP/1.1\r\n k1:v1\r\n k2:v2\r\n \r\n 请求数据 ...
- java 三大基本特征
java中的面向对象的三大基本特征是:[封装].[继承].[多态] 封装:对象要有一个明确的边界:边界的划分(对象各司其职.对象的粒度.对象的可重用性) 属性(bean.pojo):私有的privat ...
- 解决SublimeText 3无法安装Package Control的问题
"GOOD 解决SublimeText 3无法安装Package Control的问题 2019年4月6日Sublime Text3更新至3.2.1(BUILD 3207)版本,Sublim ...