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 相关文章推荐
使用Post提交时须将空格转换成加号的解释
Jan 14 Javascript
javascript中递归函数用法注意点
Jul 30 Javascript
JS截取字符串实例详解
Nov 24 Javascript
Javascript简单实现面向对象编程继承实例代码
Nov 27 Javascript
jquery.serialize() 函数语法及简单实例
Jul 08 Javascript
bootstrap使用validate实现简单校验功能
Dec 02 Javascript
JQuery统计input和textarea文字输入数量(代码分享)
Dec 29 Javascript
JS简单实现点击按钮或文字显示遮罩层的方法
Apr 27 Javascript
详解Vue.js之视图和数据的双向绑定(v-model)
Jun 23 Javascript
vue.js 实现点击按钮动态添加li的方法
Sep 07 Javascript
node实现mock-plugin中间件的方法
Dec 25 Javascript
JS实现扫码枪扫描二维码功能
Jan 03 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
php使用sql数据库 获取字段问题介绍
2013/08/12 PHP
Yii实现单用户博客系统文章详情页插入评论表单的方法
2015/12/28 PHP
php fseek函数读取大文件两种方法
2016/10/12 PHP
php socket通信简单实现
2016/11/18 PHP
php 实现银联商务H5支付的示例代码
2019/10/12 PHP
给文字加上着重号的JS代码
2013/11/12 Javascript
jquery的ajax和getJson跨域获取json数据的实现方法
2014/02/04 Javascript
jquery实现不同大小浏览器使用不同的css样式表的方法
2014/04/02 Javascript
AngularJS页面访问时出现页面闪烁问题的解决
2016/03/06 Javascript
jQuery中事件与动画的总结分享
2016/05/24 Javascript
JS实现的自定义显示加载等待图片插件(loading.gif)
2016/06/17 Javascript
javascript加载xml 并解析各节点的值(实现方法)
2016/10/12 Javascript
解决Window10系统下Node安装报错的问题分析
2016/12/13 Javascript
JavaScript 动态三角函数实例详解
2017/01/08 Javascript
vue elementUI tree树形控件获取父节点ID的实例
2018/09/12 Javascript
零基础之Node.js搭建API服务器的详解
2019/03/08 Javascript
Layui 带多选框表格监听事件以及按钮自动点击写法实例
2019/09/02 Javascript
vue之组件内监控$store中定义变量的变化详解
2019/11/08 Javascript
[02:07]TI9显影之尘系列 - Vici Gaming
2019/08/20 DOTA
Python提示[Errno 32]Broken pipe导致线程crash错误解决方法
2014/11/19 Python
在Python中使用Mako模版库的简单教程
2015/04/08 Python
Python实现分割文件及合并文件的方法
2015/07/10 Python
基于python实现雪花算法过程详解
2019/11/16 Python
Python-jenkins模块之folder相关操作介绍
2020/05/12 Python
详解numpy1.19.4与python3.9版本冲突解决
2020/12/15 Python
python 数据类型强制转换的总结
2021/01/25 Python
大学生农村教师实习自我鉴定
2013/09/21 职场文书
天鹅的故事教学反思
2014/02/04 职场文书
鲜花方阵解说词
2014/02/13 职场文书
考察现实表现材料
2014/05/19 职场文书
优秀员工评优方案
2014/06/13 职场文书
2014年销售工作总结范文
2014/12/01 职场文书
五好家庭事迹材料
2014/12/20 职场文书
2019年度政务公开考核工作总结模板
2019/11/11 职场文书
在JavaScript中如何使用宏详解
2021/05/06 Javascript
如何使用Tkinter进行窗口的管理与设置
2021/06/30 Python