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: ...
随机推荐
- php之上传图片及传数据到mysql
index.html <form action="php.php" method="post" enctype="multipart/form- ...
- node.js版本管理(Win) --- nvm-window
目录 1. 安装 2. 使用 1. 安装 去往Git链接:https://github.com/coreybutler/nvm-windows. 点击下载链接: 选择第一个nvm-noinstall. ...
- zlog 纯C日志函数库的简单使用方法
zlog简述: log是一个高性能.线程安全.灵活.概念清晰的纯C日志函数库. 事实上,在C的世界里面没有特别好的日志函数库(就像JAVA里面的的log4j,或者C++的log4cxx).C程序员都喜 ...
- 修改Linux内核参数提高Nginx服务器在高的时候的性能
并发 Linux下高并发的Nginx服务器,当TCP TIME_WAIT套接字数量经常达到两.三万,服务器很容易被拖死.通过修改Linux内核参数,可以减少Nginx服务器的TIME_WAIT套接字数 ...
- <a href="#">什么意思
转自:https://zhidao.baidu.com/question/67668291.html <a href="#">是链接到本页,因为你有的时候需要有个链接的 ...
- web面试常见问题
1事件继承 function ClassA(sColor) { this.color = sColor; this.sayColor = function () { al ...
- Flutter实战视频-移动电商-13.首页_广告Banner组件制作
13.首页_广告Banner组件制作 主要是做这个小广告条. 其实就是读取一个图片做一个widget放到这里 使用stlessW快速生成 定义一个变量存放图片的url地址: 这样我们的广告条就写完了 ...
- python之文件的读写(1)
真的崩溃,刚写完的笔记由于点错了,现在特么又要重新写了. 崩溃呀.......... 之前的废话就不再重复了,直接进入正题吧. 今天小R 学了一天的NP课程,但是python还是不能忘得,所以晚上又 ...
- 动态加载dll
extern "C" MMUPDATENOTIFY_IMPEXP bool _cdecl NotifyThrift(char* chThriftIp, char* chPor) H ...
- 336. Palindrome Pairs(can't understand)
Given a list of unique words, find all pairs of distinct indices (i, j) in the given list, so that t ...