深入理解javascript之this
javascript中的this含义很丰富,它能够是全局对象,当前对象或者是随意对象,这都取决于函数的调用方式。函数有下面几种调用方式:作为对象方法调用、作为函数调用、作为构造函数调用、apply或call调用。
对象方法调用
作为对象方法调用的时候。this会被绑定到该对象。
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
this.x = this.x + x;
this.y = this.y + y;
}
};
point.moveTo(1, 1)//this 绑定到当前对象,即 point 对象
这里我想强调一点内容,就是this是在函数运行的时候去获取相应的值,而不是函数定义时。即使是对象方法调用,假设该方法的函数属性以函数名的形式传入别的作用域,也会改变this的指向。我举一个样例:
var a = {
aa : 0,
bb : 0,
fun : function(x,y){
this.aa = this.aa + x;
this.bb = this.bb + y;
}
};
var aa = 1;
var b = {
aa:0,
bb:0,
fun : function(){return this.aa;}
}
a.fun(3,2);
document.write(a.aa);//3,this指向对象本身
document.write(b.fun());//0,this指向对象本身
(function(aa){//注意传入的是函数。而不是函数运行的结果
var c = aa();
document.write(c);//1 , 因为fun在该处运行,导致this不再指向对象本身。而是这里的window
})(b.fun);
这样就明确了吧。这是一个easy混淆的地方。
函数调用
函数也能够直接被调用,这个时候this被绑定到了全局对象。
var x = 1;
function test(){
this.x = 0;
}
test();
alert(x); //0
但这样就会出现一些问题。就是在函数内部定义的函数。其this也会指向全局。而和我们希望的恰恰相反。代码例如以下:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
// 内部函数
var moveX = function(x) {
this.x = x;//this 绑定到了全局
};
// 内部函数
var moveY = function(y) {
this.y = y;//this 绑定到了全局
};
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>0
point.y; //==>0
x; //==>1
y; //==>1
我们会发现不但我们希望的移动呢效果没有完毕,反而会多出两个全局变量。
那么怎样解决呢?仅仅要要进入函数中的函数时将this保存到一个变量中,再运用该变量就可以。代码例如以下:
var point = {
x : 0,
y : 0,
moveTo : function(x, y) {
var that = this;
// 内部函数
var moveX = function(x) {
that.x = x;
};
// 内部函数
var moveY = function(y) {
that.y = y;
}
moveX(x);
moveY(y);
}
};
point.moveTo(1, 1);
point.x; //==>1
point.y; //==>1
构造函数调用
在javascript中自己创建构造函数时能够利用this来指向新创建的对象上。
这样就能够避免函数中的this指向全局了。
var x = 2;
function test(){
this.x = 1;
}
var o = new test();
alert(x); //2
apply或call调用
这两个方法能够切换函数运行的上下文环境。也就是改变this绑定的对象。
apply和call比較类似,差别在于传入參数时一个要求是数组。一个要求是分开传入。所以我们以apply为例:
<pre name="code" class="html">var name = "window";
var someone = {
name: "Bob",
showName: function(){
alert(this.name);
}
};
var other = {
name: "Tom"
};
someone.showName(); //Bob
someone.showName.apply(); //window
someone.showName.apply(other); //Tom
能够看到,正常訪问对象中方法时,this指向对象。
使用了apply后,apply无參数时,this的当前对象是全局,apply有參数时,this的当前对象就是该參数。
箭头函数调用
这里须要补充一点内容。就是在下一代javascript标准ES6中的箭头函数的 this始终指向函数定义时的 this,而非运行时。我们通过一个样例来理解:
var o = {
x : 1,
func : function() { console.log(this.x) },
test : function() {
setTimeout(function() {
this.func();
}, 100);
}
};
o.test(); // TypeError : this.func is not a function
上面的代码会出现错误,由于this的指向从o变为了全局。我们须要改动上面的代码例如以下:
var o = {
x : 1,
func : function() { console.log(this.x) },
test : function() {
var _this = this;
setTimeout(function() {
_this.func();
}, 100);
}
};
o.test();
通过使用外部事先保存的this即可了。这里就能够利用到箭头函数了。我们刚才说过,箭头函数的 this始终指向函数定义时的 this,而非运行时。所以我们将上面的代码改动例如以下:
var o = {
x : 1,
func : function() { console.log(this.x) },
test : function() {
setTimeout(() => { this.func() }, 100);
}
};
o.test();
这回this就指向o了,我们还须要注意一点的就是这个this是不会改变指向对象的,我们知道call和apply能够改变this的指向,可是在箭头函数中是无效的。
var x = 1,
o = {
x : 10,
test : () => this.x
}; o.test(); // 1
o.test.call(o); // 依旧是1
这样就能够明确各种情况下this绑定对象的差别了。
深入理解javascript之this的更多相关文章
- 深入理解javascript原型和闭包 (转)
该教程绕开了javascript的一些基本的语法知识,直接讲解javascript中最难理解的两个部分,也是和其他主流面向对象语言区别最大的两个部分--原型和闭包,当然,肯定少不了原型链和作用域链.帮 ...
- 深入理解JavaScript运行机制
深入理解JavaScript运行机制 前言 本文是写作在给团队新人培训之际,所以其实本文的受众是对JavaScript的运行机制不了解或了解起来有困难的小伙伴.也就是说,其实真正的原理和本文阐述的并不 ...
- 深入理解javascript系列(4):立即调用的函数表达式
本文来自汤姆大叔 前言 大家学JavaScript的时候,经常遇到自执行匿名函数的代码,今天我们主要就来想想说一下自执行. 在详细了解这个之前,我们来谈了解一下“自执行”这个叫法,本文对这个功能的叫法 ...
- 深入理解javascript原型和闭包系列
从下面目录中可以看到,本系列有16篇文章,外加两篇后补的,一共18篇文章.写了半个月,从9月17号开始写的.每篇文章更新时,读者的反馈还是可以的,虽然不至于上头条,但是也算是中规中矩,有看的人,也有评 ...
- 深入理解JavaScript的闭包特性如何给循环中的对象添加事件
初学者经常碰到的,即获取HTML元素集合,循环给元素添加事件.在事件响应函数中(event handler)获取对应的索引.但每次获取的都是最后一次循环的索引.原因是初学者并未理解JavaScript ...
- 深入理解javascript原型和闭包(1)——一切都是对象
“一切都是对象”这句话的重点在于如何去理解“对象”这个概念. ——当然,也不是所有的都是对象,值类型就不是对象. 首先咱们还是先看看javascript中一个常用的函数——typeof().typeo ...
- 深入理解javascript原型和闭包(2)——函数和对象的关系
上文(理解javascript原型和作用域系列(1)——一切都是对象)已经提到,函数就是对象的一种,因为通过instanceof函数可以判断. var fn = function () { }; co ...
- 深入理解javascript原型和闭包(3)——prototype原型
既typeof之后的另一位老朋友! prototype也是我们的老朋友,即使不了解的人,也应该都听过它的大名.如果它还是您的新朋友,我估计您也是javascript的新朋友. 在咱们的第一节(深入理解 ...
- 深入理解javascript原型和闭包(4)——隐式原型
注意:本文不是javascript基础教程,如果你没有接触过原型的基本知识,应该先去了解一下,推荐看<javascript高级程序设计(第三版)>第6章:面向对象的程序设计. 上节已经提到 ...
- 深入理解javascript原型和闭包(5)——instanceof
又介绍一个老朋友——instanceof. 对于值类型,你可以通过typeof判断,string/number/boolean都很清楚,但是typeof在判断到引用类型的时候,返回值只有object/ ...
随机推荐
- WPF概述
一.概述 WPF(Windows Presentation Foundation,视窗展示[呈现.展现.显示.表示]基础)是Windows的新一代图形子系统,他为开发人员提供了统一的编程模型,可用于构 ...
- (转)dedecms [field:array runphp='yes']标签使用技巧
field支持用array获取任意字段的值:(支持标记:文章内容模板的 {dede:field name=’array’ /}.arclist.arclistsg.loop.sql 标签) 我们平时常 ...
- Android虚拟机GenyMotion-- 遇到的问题
问题: android studio 检测不到 genymotion 原因:没有设置genymotion的adb,也就是sdk的路径. 解决方法:打开genymotion的主页面,设置sdk的位置为你 ...
- Oracle 用户(user)和模式(schema)的区别
概述: (一)什么Oracle叫用户(user): A user is a name defined in the database that can connect to and access ob ...
- JavaScript--数组--sort比较器
因为原装的sort这个API其实是先把要比较的数转换为字符串再进行比较的,所以并不好用 所以准备自定义一个比较器函数: //sort原理--->sort(arr,compare) functio ...
- cas sso原理(转)
采用CAS原理构建单点登录 企业的信息化过程是一个循序渐进的过程,在企业各个业务网站逐步建设的过程中,根据各种业务信息水平的需要构建了相应的应用系统,由于这些应用系统一般是 在不同的时期开发完成的,各 ...
- Spring4.0学习笔记(9) —— Spring泛型依赖注入
1.定义基础仓库 package com.spring.generic.di; public class BaseRepository<T> { } 2.定义基础服务层 package c ...
- sublime2开发Python的编码问题
在sublime2文本编辑器直接开发python程序会出现错误 Traceback (most recent call last): File ".\sublime_plugin.py&qu ...
- python运维开发之第八天(socket)
什么是 Socket? Socket又称"套接字",应用程序通常通过"套接字"向网络发出请求或者应答网络请求,使主机间或者一台计算机上的进程间可以通讯. soc ...
- 实验七:Linux内核如何装载和启动一个可执行程序
原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 题目自拟,内容围绕对Linu ...