在JS中,this指向是一个难点,在本文中讲解几种常见的this指向问题,并介绍一下call,apply,bind这三个函数的用法。

一、常见的this指向情况

  首先要明白一点就是,函数里面才会有this,而this指向是由函数执行的方式来决定的,并且this指向的一定是对象,常见的有三种情况:

  1. 函数名(),即函数名加括号自执行,该函数里面的this指向window对象;
  2. 对象.方法(),即对象点属性方法加括号执行,此方法内的this指向该对象;
  3. 无论什么形式的事件函数,函数内部的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,让我们先来看看它们的用法和不同之处。

  1. call:

    在函数执行阶段使用,可以改变this指向;
    call的第一个参数代表函数的this指向;
    原函数的第一个形参对应call的第二位实参,第二个形参对应call的第三位实参,以此类推。

  2. apply:

    在函数执行阶段使用,可以改变this指向;
    apply的第一个参数代表函数的this指向;
    apply的第二个参数是个数组,数组第一位对应原函数第一个形参,以此类推。

  3. 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浅析的更多相关文章

  1. call,apply,bind的用法

    关于call,apply,bind这三个函数的用法,是学习javascript这门语言无法越过的知识点.下边我就来好好总结一下它们三者各自的用法,及常见的应用场景. 首先看call这个函数,可以理解成 ...

  2. JavaScript中call,apply,bind方法的总结。

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...

  3. call(),apply(),bind()与回调

    1.call(),apply(),bind()方法 JavaScript 中通过call或者apply用来代替另一个对象调用一个方法,将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定 ...

  4. JS 的 call apply bind 方法

    js的call apply bind 方法都很常见,目的都是为了改变某个方法的执行环境(context) call call([thisObj[,arg1[, arg2[,   [,.argN]]]] ...

  5. javascript-this,call,apply,bind简述2

    上节我们一起研究了this这个小兄弟,得出一个结论,this指向调用this所在函数(或作用域)的那个对象或作用域.不太理解的朋友可以看看上节的内容,这次我们主要探讨一下call(),apply(), ...

  6. javascript-this,call,apply,bind简述1

    最近在系统的学习面向对象方面的知识,遇到的最大拦路虎就数this的指向,call,apply,bind函数的使用,单独抽出一天时间把这几个烦人的家伙搞定,去学习更深入的内容. 首先介绍一下this的一 ...

  7. call,apply,bind方法的总结

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...

  8. JavaScript中call,apply,bind方法的总结

    原文链接:http://www.cnblogs.com/pssp/p/5215621.html why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之 ...

  9. call, apply,bind 方法解析

    call(), apply(),bind() 三者皆为Function的方法 call(),apply()的作用是调用方法,并改变函数运行时的context(作用上下文) bind() 的作用是引用方 ...

  10. JS中call,apply,bind方法的总结

    why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user: "小马扎", fn: ...

随机推荐

  1. BZOJ_3729_Gty的游戏_博弈论+splay+dfs序

    BZOJ_3729_Gty的游戏_博弈论+splay+dfs序 Description 某一天gty在与他的妹子玩游戏. 妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子 ...

  2. [APIO 2015] 雅加达的摩天楼

    [题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=4070 [算法] 考虑将每个"Doge"向其所能到达的楼连边 直接 ...

  3. zabbix snmp、jmx配置使用

    SNMP: snmp是很古老的监控,我萌几乎可以在所有设备上看到它的身影 [root@linux-node1 ~]# yum install net-snmp net-snmp-libs net-sn ...

  4. dubbo 学习笔记 -- provider端

    服务端的配置文件:    provider.xml <?xml version="1.0" encoding="UTF-8"?> <beans ...

  5. 招聘.Net中高级软件研发工程师

    岗位职责: 1.参与国土不动产系列软件需求分析.系统架构分析与设计: 2.为产品中的复杂功能编写产品开发需求文档: 3.根据设计文档或需求说明完成代码编写.调试.测试和维护: 4.配合上级进行技术决策 ...

  6. Spring Boot2中配置HTTPS

    1.生成证书 使用jdk,jre中的keytool.exe生成自签名的证书,需要配置JAVA_HOME和path环境变量,即jdk的环境变量.命令如下: keytool -genkey -alias ...

  7. 面试lua笔试题各种坑

    替换字符串"abcdefgh" 中的"abc"为"ddc" local str ="abcdefgh"; b = str ...

  8. Android NDK开发指南(二)Android.mk文件

    http://www.cnblogs.com/yaozhongxiao/archive/2012/03/06/2382225.html 1.  概述 Android.mk文件是用来描述build sy ...

  9. Unity3D研究院之IOS Android支持中文与本地文件的读取写

       前几天有个朋友问我为什么在IOS平台中可以正常的读写文件可是在Android平台中就无法正常的读写.当时因为在上班所以我没时间来帮他解决,晚上回家后我就拿起安卓手机真机调试很快就定位问题所在,原 ...

  10. SpringBoot2.0基础案例(01):环境搭建和RestFul风格接口

    一.SpringBoot 框架的特点 1.SpringBoot2.0 特点 1)SpringBoot继承了Spring优秀的基因,上手难度小 2)简化配置,提供各种默认配置来简化项目配置 3)内嵌式容 ...