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小框架 fly javascript framework
Nov 26 Javascript
引用 js在IE与FF之间的区别详细解析
Nov 20 Javascript
JavaScript中跨域调用Flash的方法
Aug 11 Javascript
jQuery实现的进度条效果
Jul 15 Javascript
微信小程序开发探究
Dec 27 Javascript
JS三目运算(三元运算)方法详解
Mar 01 Javascript
关于微信公众号开发无法支付的问题解决
Dec 28 Javascript
Vue匿名插槽与作用域插槽的合并和覆盖行为
Apr 22 Javascript
解决vue项目中页面调用数据 在数据加载完毕之前出现undefined问题
Nov 14 Javascript
jquery实现弹窗(系统提示框)效果
Dec 10 jQuery
javascript设计模式 ? 命令模式原理与用法实例分析
Apr 20 Javascript
ES6的循环与可迭代对象示例详解
Jan 31 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下pdo的mysql事务处理用法实例
2014/12/27 PHP
wordpress安装过程中遇到中文乱码的处理方法
2015/04/21 PHP
利用google提供的API(JavaScript接口)获取网站访问者IP地理位置的代码详解
2010/07/24 Javascript
JavaScript(JS) 压缩 / 混淆 / 格式化 批处理工具
2010/12/10 Javascript
使用jQuery获取data-的自定义属性
2015/11/10 Javascript
以jQuery中$.Deferred对象为例讲解promise对象是如何处理异步问题
2015/11/13 Javascript
2016年最热门的15 款代码语法高亮工具,美化你的代码
2016/01/06 Javascript
利用webstrom调试Vue.js单页面程序的方法教程
2017/06/06 Javascript
JS+canvas画一个圆锥实例代码
2017/12/13 Javascript
详解react-redux插件入门
2018/04/19 Javascript
vue.js数据绑定操作详解
2018/04/23 Javascript
js正则表达式校验指定字符串的方法
2018/07/23 Javascript
layui 给数据表格加序号的方法
2018/08/20 Javascript
js实现GIF动图分解成多帧图片上传
2019/10/24 Javascript
vue实现分页加载效果
2019/12/24 Javascript
微信小程序实现滑动操作代码
2020/04/23 Javascript
[00:35]可解锁地面特效
2018/12/20 DOTA
解析Python编程中的包结构
2015/10/25 Python
Python基于PyGraphics包实现图片截取功能的方法
2017/12/21 Python
python3+PyQt5 创建多线程网络应用-TCP客户端和TCP服务器实例
2019/06/17 Python
浅谈PyQt5 的帮助文档查找方法,可以查看每个类的方法
2019/06/25 Python
简单了解python PEP的一些知识
2019/07/13 Python
python开发入门——列表生成式
2020/09/03 Python
websocket+sockjs+stompjs详解及实例代码
2018/11/30 HTML / CSS
美国在线鲜花速递:ProFlowers
2017/01/05 全球购物
YSL圣罗兰美妆官方旗舰店:购买YSL口红
2018/04/16 全球购物
函数指针的定义是什么
2016/08/14 面试题
Ajax的工作原理
2015/12/04 面试题
求职面试个人自我评价
2014/02/28 职场文书
《雪儿》教学反思
2014/04/17 职场文书
小班上学期幼儿评语
2014/12/30 职场文书
民事上诉状范文
2015/05/22 职场文书
幼儿园大班教学反思
2016/03/02 职场文书
oracle表分区的概念及操作
2021/04/24 Oracle
MySQL query_cache_type 参数与使用详解
2021/07/01 MySQL
python如何利用cv2.rectangle()绘制矩形框
2022/12/24 Python