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 相关文章推荐
延时重复执行函数 lLoopRun.js
May 08 Javascript
javascript 循环调用示例介绍
Nov 20 Javascript
node.js中的buffer.Buffer.isBuffer方法使用说明
Dec 14 Javascript
纯js实现无限空间大小的本地存储
Jun 18 Javascript
Js与Jq获取浏览器和对象值的方法
Mar 18 Javascript
JS组件Bootstrap Select2使用方法解析
May 30 Javascript
js 判断一组日期是否是连续的简单实例
Jul 11 Javascript
bootstrap基础知识学习笔记
Nov 02 Javascript
JS 循环li添加点击事件 (闭包的应用)
Dec 10 Javascript
Vue中的字符串模板的使用
May 17 Javascript
使用js实现一个简单的滚动条过程解析
Sep 10 Javascript
适合后台管理系统开发的12个前端框架(小结)
Jun 29 Javascript
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
德劲1107的电路分析与打磨
2021/03/02 无线电
php 验证码制作(网树注释思想)
2009/07/20 PHP
windows平台中配置nginx+php环境
2015/12/06 PHP
PHP大神的十大优良习惯
2016/09/14 PHP
PHP排序算法之希尔排序(Shell Sort)实例分析
2018/04/20 PHP
在laravel-admin中列表中禁止某行编辑、删除的方法
2019/10/03 PHP
Stop SQL Server
2007/06/21 Javascript
js 事件小结 表格区别
2007/08/13 Javascript
Notify - 基于jquery的消息通知插件
2011/10/18 Javascript
50款非常棒的 jQuery 插件分享
2012/03/29 Javascript
js监听键盘事件示例代码
2013/07/26 Javascript
JavaScript转换二进制编码为ASCII码的方法
2015/04/16 Javascript
js弹出框、对话框、提示框、弹窗实现方法总结(推荐)
2016/05/31 Javascript
vuejs在解析时出现闪烁的原因及防止闪烁的方法
2016/09/19 Javascript
JavaScript使用链式方法封装jQuery中CSS()方法示例
2017/04/07 jQuery
JS实现获取图片大小和预览的方法完整实例【兼容IE和其它浏览器】
2017/04/24 Javascript
微信小程序 新建登录页并实现tabBar隐藏
2017/06/13 Javascript
使用JS中的Replace()方法遇到的问题小结
2017/10/20 Javascript
谈谈JS中的!!
2017/12/07 Javascript
vue组件实现可搜索下拉框扩展
2020/10/23 Javascript
Vue 组件参数校验与非props特性的方法
2019/02/12 Javascript
Python使用asyncio包处理并发详解
2017/09/09 Python
python探索之BaseHTTPServer-实现Web服务器介绍
2017/10/28 Python
Python+OpenCV实现旋转文本校正方式
2020/01/09 Python
django修改models重建数据库的操作
2020/03/31 Python
python 通过文件夹导入包的操作
2020/06/01 Python
中国高端鲜花第一品牌:roseonly(一生只送一人)
2017/02/12 全球购物
计算机网络及管理学专业求职信
2014/06/05 职场文书
2014乡镇党政班子四风问题思想汇报
2014/09/14 职场文书
普通党员个人整改措施
2014/10/27 职场文书
工作年限证明模板
2014/11/01 职场文书
2016年中学清明节活动总结
2016/04/01 职场文书
小学秋季运动会加油口号及加油稿
2019/08/19 职场文书
MySQL中distinct和count(*)的使用方法比较
2021/05/26 MySQL
SpringBoot连接MySQL获取数据写后端接口的操作方法
2021/11/02 MySQL
Mysql如何实现不存在则插入,存在则更新
2022/03/25 MySQL