JavaScript中的this,call,apply使用及区别详解


Posted in Javascript onJanuary 29, 2016

学习起因:

在之前的JavaScript学习中,this,call,apply总是让我感到迷惑,但是他们的运用又非常的广泛。遂专门花了一天,来弄懂JavaScript的this,call,apply。

中途参考的书籍也很多,以《JavaScript设计模式与开发实践》为主,《JavaScript高级程序设计》、《你不知道的JavaScript》为辅。这三本书对我理解this,call,apply都起了很大的帮助。

this

首先,我们先讲述this。

在《JavaScript设计模式与开发实践》关于this的描述中,我认为有一句话切中了this的核心要点。那就是:

JavaScript的this总是指向一个对象
具体到实际应用中,this的指向又可以分为以下四种:

  1. 作为对象的方法调用
  2. 作为普通函数调用
  3. 构造器调用
  4. apply和call调用

接下来我们去剖析前3点,至于第4点的apply和call调用,会在call和apply部分详细讲解。

1.作为对象的方法调用

说明:作为对象方法调用时,this指向该对象。
举例:

/**
 * 1.作为对象的方法调用
 *
 * 作为对象方法调用时,this指向该对象。
 */

var obj = {
 a: 1,
 getA: function() {
  console.log(this === obj);
  console.log(this.a);
 }
};

obj.getA(); // true , 1

2.作为普通函数调用

说明:作为普通函数调用时,this总是指向全局对象(浏览器中是window)。
举例:

/**
 * 2.作为普通函数调用
 *
 * 不作为对象属性调用时,this必须指向一个对象。那就是全局对象。
 */

window.name = 'globalName';

var getName = function() {
 console.log(this.name);
};

getName(); // 'globalName'

var myObject = {
 name: "ObjectName",
 getName: function() {
  console.log(this.name)
 }
};

myObject.getName(); // 'ObjectName'

// 这里实质上是把function() {console.log(this.name)}
// 这句话赋值给了theName。thisName在全局对象中调用,自然读取的是全局对象的name值
var theName = myObject.getName;

theName(); // 'globalName'

3.构造器调用

说明:作为构造器调用时,this指向返回的这个对象。
举例:

/**
 * 3.作为构造器调用
 * 
 * 作为构造器调用时,this指向返回的这个对象。
 */

var myClass = function() {
 this.name = "Lxxyx";
};

var obj = new myClass();

console.log(obj.name); // Lxxyx
console.log(obj) // myClass {name: "Lxxyx"}

但是如果构造函数中手动指定了return其它对象,那么this将不起作用。
如果return的是别的数据类型,则没有问题。

var myClass = function() {
 this.name = "Lxxyx";
 // 加入return时,则返回的是别的对象。this不起作用。
 return {
  name:"ReturnOthers"
 }
};

var obj = new myClass();
console.log(obj.name); // ReturnOthers

4.Call和Apply

Call和Apply的用途一样。都是用来指定函数体内this的指向。

Call和Apply的区别

Call:第一个参数为this的指向,要传给函数的参数得一个一个的输入。
Apply:第一个参数为this的指向,第二个参数为数组,一次性把所有参数传入。

如果第一个参数为null,则this指向调用的本身。

1.改变this指向

说明:这是call和apply最常用的用途了。用于改变函数体内this的指向。
举例:

var name = "GlobalName"

var func = function() {
 console.log(this.name)
};

func(); // "GlobalName"

var obj = {
 name: "Lxxyx",
 getName: function() {
  console.log(this.name)
 }
};

obj.getName.apply(window) // "GlobalName" 将this指向window
func.apply(obj) // "Lxxyx" 将this指向obj

2.借用其它对象的方法

这儿,我们先以一个立即执行匿名函数做开头:

(function(a, b) {
 console.log(arguments) // 1,2
 // 调用Array的原型方法
 Array.prototype.push.call(arguments, 3);
 console.log(arguments) // 1,2,3
})(1,2)

函数具有arguments属性,而arguments是一个类数组。
但是arguments是不能直接调用数组的方法的,所以我们要用call或者apply来调用Array对象的原型方法。
原理也很容易理解,比如刚才调用的是push方法,而push方法在谷歌的v8引擎中,源代码是这样的:

function ArrayPush() {
 var n = TO_UINT32(this.length); // 被push对象的长度
 var m = % _ArgumentsLength(); // push的参数个数
 for (var i = 0; i < m; i++) {
  this[i + n] = % _Arguments(i); // 复制元素
 }
 this.length = n + m; //修正length属性
 return this.length;
}

它只与this有关,所以只要是类数组对象,都可以调用相关方法去处理。

这部分内容比较复杂,再加上自己水平也不太够。所以推荐有条件的同学去购买相关书籍,或者等我的后续博客文章。

感想

通过对这部分的学习,算是加深了对JavaScript的理解。最直观的表现就是,去看一些优秀框架的源代码时,不再是被this,call,apply,bind绕的晕乎乎的。还是很开心的~

下一段时间,准备深入探索一下日常学习和使用的CSS。毕竟JavaScript学了,HTML和CSS也不能落下。

Javascript 相关文章推荐
js下用eval生成JSON对象
Sep 17 Javascript
jquery连缀语法如何实现
Nov 29 Javascript
node.js实现逐行读取文件内容的代码
Jun 27 Javascript
jquery中的常用事件bind、hover、toggle等示例介绍
Jul 21 Javascript
jQuery调取jSon数据并展示的方法
Jan 29 Javascript
深入理解JavaScript中的call、apply、bind方法的区别
May 30 Javascript
vue中配置mint-ui报css错误问题的解决方法
Oct 11 Javascript
vue组件传值的实现方式小结【三种方式】
Feb 05 Javascript
使用vue打包进行云服务器上传的问题
Mar 02 Javascript
微信浏览器左上角返回按钮监听的实现
Mar 04 Javascript
vue自定义指令和动态路由实现权限控制
Aug 28 Javascript
vue3.0封装轮播图组件的步骤
Mar 04 Vue.js
javascript实现tab响应式切换特效
Jan 29 #Javascript
JavaScript SweetAlert插件实现超酷消息警告框
Jan 28 #Javascript
JS组件系列之Bootstrap Icon图标选择组件
Jan 28 #Javascript
很不错的两款Bootstrap Icon图标选择组件
Jan 28 #Javascript
Angular实现form自动布局
Jan 28 #Javascript
理解javascript中的MVC模式
Jan 28 #Javascript
jQuery获取checkbox选中的值
Jan 28 #Javascript
You might like
用header 发送cookie的php代码
2007/03/16 PHP
javascript作用域和闭包使用详解
2014/04/25 Javascript
JavaScript中textRange对象使用方法小结
2015/03/24 Javascript
javascript动态生成树形菜单的方法
2015/11/14 Javascript
举例讲解JavaScript中关于对象操作的相关知识
2015/11/16 Javascript
node.js入门实例helloworld详解
2015/12/23 Javascript
js实现文本框输入文字个数限制代码
2015/12/25 Javascript
js实现导航栏中英文切换效果
2017/01/16 Javascript
jQuery加载及解析XML文件的方法实例分析
2017/01/22 Javascript
详解HTTPS 的原理和 NodeJS 的实现
2017/07/04 NodeJs
jQuery图片缩放插件smartZoom使用实例详解
2017/08/25 jQuery
JavaScript寄生组合式继承实例详解
2018/01/06 Javascript
vue之debounce属性被移除及处理详解
2019/11/13 Javascript
java遇到微信小程序 &quot;支付验证签名失败&quot; 问题解决
2019/12/22 Javascript
JS原型prototype和__proto__用法实例分析
2020/03/14 Javascript
JavaScript实现移动端带transition动画的轮播效果
2020/03/24 Javascript
js实现盒子拖拽动画效果
2020/08/09 Javascript
[07:20]2014DOTA2西雅图国际邀请赛 选手讲解积分赛第二天
2014/07/11 DOTA
[00:58]PWL开团时刻DAY5——十人开雾0换5
2020/11/04 DOTA
Python入门之modf()方法的使用
2015/05/15 Python
深入理解python中的闭包和装饰器
2016/06/12 Python
Python实现批量更换指定目录下文件扩展名的方法
2016/09/19 Python
virtualenv实现多个版本Python共存
2017/08/21 Python
TensorFlow 实战之实现卷积神经网络的实例讲解
2018/02/26 Python
python3库numpy数组属性的查看方法
2018/04/17 Python
Python实现自定义函数的5种常见形式分析
2018/06/16 Python
Python unittest单元测试框架总结
2018/09/08 Python
python递归下载文件夹下所有文件
2019/08/31 Python
使用Python给头像加上圣诞帽或圣诞老人小图标附源码
2019/12/25 Python
Django ORM判断查询结果是否为空,判断django中的orm为空实例
2020/07/09 Python
Python datetime 如何处理时区信息
2020/09/02 Python
Android interview questions
2016/12/25 面试题
幼师专业毕业生自荐信
2013/09/29 职场文书
平面设计自荐信
2013/10/07 职场文书
大二学生学年自我鉴定
2014/09/12 职场文书
php远程请求CURL案例(爬虫、保存登录状态)
2021/04/01 PHP