最近的文章基本都是总结javascript基础内容的,因为我觉得这些东西很重要。而且很多时候你觉得你理解了,其实并没有你自认为的那么理解。十月份没怎么写文章,因为国庆出去玩的比较久,心变野了,现在是时候重新回到学习的轨迹了,今天要总结的是javascript中的this.

介绍this之前,先来两句话,这两句话比较重要,可以说贯穿全文。

1、this的最终指向的是那个调用它的对象

2、如果一个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象

下面通过一些代码示例来讲解this

1、window中的this

demo1

function test1(){
    this.x = 1;
console.log(this.x);
  }
test1(); // function test2(){
var y = 2;
console.log(this.y); //undefined
console.log(this);  //Window
}
test2();

上面的两个例子中,都是属于属于全局性调用,因此this就代表全局对象。也就是为什么test2打印出来的this.y会是undefined,因为this指向了 window.

2、在对象中使用this 

demo2

var x=0;
var obj={
x:1,
fn:function(){
console.log(this.x);
}
}
obj.fn(); //

这里的this指向对象obj,因为调用的fn是通过obj.fn()执行的。

不过这里有个注意点,就是this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,这个是比较重要的一点。为了验证这句话,稍微改造一下上面的demo2

demo3

var x=0;
var obj={
x:1,
fn:function(){
console.log(this.x);
}
}
obj.fn(); // 1 跟上面的代码一样 // 修改了这里
var obj2=obj.fn;
obj2(); //

demo3中和demo2的不同之处在于,没有直接调用obj里面的fn函数,而是将其赋值给obj2,最终通过obj2来调用fn函数。

而obj2属于全局变量,因为fn里面的this指向了 window。这个也验证了上面那句话: this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁

demo4

var obj = {
x:1,
y:{
fn:function(){
console.log(this.x); //undefined
}
}
}
obj.y.fn();

如果一个对象中又包含有其他对象,this仅仅会指向它的上一级对象。
就像demo4中,fn里面调用this.x,这个this只会指向fn的上一级对象y。y中没有x这个变量,所以返回的是undefined。

稍微改造一下demo4,再次来验证一下:this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁

demo5

var obj = {
x:1,
y:{
x:2,
fn:function(){
console.log(this.x); //undefined
}
}
}
var obj2=obj.y.fn;
obj2(); // 因为此时fn中的this指向了window

3、在构造函数中使用this

demo6

function Fn(){
this.x=1;
}
var myFn=new Fn();
console.log(myFn.x); //

如果函数倾向于和 new 关键词一块使用,则我们称这个函数是构造函数, 在函数内部,this 指向新创建的对象。也就是说,这个this不是指向函数Fn,而是指向它的实例 myFn。

4、call和apply,改变this指向(这里顺便把call和apply给介绍了

在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,也就是说,是为了改变函数体内部 this 的指向。

call和apply的区别就在于传递方式的不同,call在接收指定参数的形式是 someMethod.call(obj, arg1, arg2);

而apply在接收指定参数时的形式是 someMethod.apply(obj, [arg1, arg2]).或者someMethod.apply(obj, arg1),但是这个arg1必须是一个类数组对象

demo7

var personA = {
name: 'kobe',
sayName: function (hobby){
console.log(this.name + ' likes ' + hobby);
}
}; personA.sayName('basketball'); // 'kobe likes basketball' var personB = { name: 'James'
} personA.sayName.call(personB, 'basketball'); // 'James likes basketball'
personA.sayName.apply(personB, ['basketball']); // 'James likes basketball'

personA.sayName('basketball'); 这段代码中,调用sayName()这个方法的对象是personA,因此sayName()内部的this指向就是personA对象。
personA.sayName.call(personB, 'basketball'); 本来sayName方法的this指向是personA对象,但是调用call/apply后,this对象指向了personB对象。


也可以这么理解,personA.sayName.call(personB, 'basketball')其实就是 personB.sayName(‘basketball’);



demo8
function PersonA(name,hobby) {
this.name = name,
this.hobby = hobby,
this.say = function() {
console.log(name +" likes " + this.hobby + '.');
}
}
function PersonB(name,hobby) {
PersonA.call(this,name,hobby);
} var Fn=new PersonB('James','basketball');
Fn.say(); // James likes basketball.

虽然我们没有在PersonB对象里添加任何属性和方法,但是我们使用call()继承了原本属于PersonA 的属性和方法。就可以做到 PersonA 函数所有能做到的事情。

这里额外再穿插一下appy的使用一些场景

apply应用场景1:数组合并

var list1 = [0,1,2];
var list2 = [3,4,5];
[].push.apply(list1,list2); //或者 Array.prototype.push.apply(list1, list2); console.log(list1);// [0,1,2,3,4,5]

apply应用场景2:获取数组中的最大值或者最小值

var arr = [0,1,2,15,6];
var getMax=Math.max.apply(this,arr);
console.log(getMax); //

5、使用this的注意点

这里主要介绍 setTimeout或者setInterval中使用this的注意点

demo9

var name='james';
var person={
name:'koBe',
sayName:function(){
setTimeout(function(){
console.log(this.name);
},0);
}
}
person.sayName(); // james

因为setTimeout()这个异步函数调用的时候,内部的回调函数this的指向是window.刚好window中有一个 name为 james的标量。所以输出james.

那如何将setTimeout中的this指向 person呢。两种方式:

方法一:将this保存在一个变量中

demo10

var name='james';
var person={
name:'koBe',
sayName:function(){
var that=this; //将this存储在that中。
setTimeout(function(){
console.log(that.name);
},0);
}
}
person.sayName(); // koBe

将this保存在that中,这样,setTimeout调用this.name就变成了that.name了。

方法二:使用bind

demo11

var name='james';
var person={
name:'koBe',
sayName:function(){
setTimeout(function(){
console.log(this.name);
}.bind(this),0);
}
}
person.sayName(); // koBe

bind方法,起的作用和call,apply一样,都是改变函数/方法执行时,this的指向,确保这个函数/方法运行时this指向保持一致。

demo11中,通过bind方法将this对象绑定为person。那么回调函数在执行的时候,this指向还是person。

有误之处,欢迎指出

【原】理解javascript中的this的更多相关文章

  1. 转载 深入理解JavaScript中的this关键字

    转载原地址: http://www.cnblogs.com/rainman/archive/2009/05/03/1448392.html 深入理解JavaScript中的this关键字   1. 一 ...

  2. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

  3. 深入理解JavaScript中创建对象模式的演变(原型)

    深入理解JavaScript中创建对象模式的演变(原型) 创建对象的模式多种多样,但是各种模式又有怎样的利弊呢?有没有一种最为完美的模式呢?下面我将就以下几个方面来分析创建对象的几种模式: Objec ...

  4. 深入理解JavaScript中的属性和特性

    深入理解JavaScript中的属性和特性 JavaScript中属性和特性是完全不同的两个概念,这里我将根据自己所学,来深入理解JavaScript中的属性和特性. 主要内容如下: 理解JavaSc ...

  5. 深入理解javascript中执行环境(作用域)与作用域链

    深入理解javascript中执行环境(作用域)与作用域链 相信很多初学者对与javascript中的执行环境与作用域链不能很好的理解,这里,我会按照自己的理解同大家一起分享. 一般情况下,我们把执行 ...

  6. 【干货理解】理解javascript中实现MVC的原理

    理解javascript中的MVC MVC模式是软件工程中一种软件架构模式,一般把软件模式分为三部分,模型(Model)+视图(View)+控制器(Controller); 模型:模型用于封装与应用程 ...

  7. 理解javascript中的策略模式

    理解javascript中的策略模式 策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换. 使用策略模式的优点如下: 优点:1. 策略模式利用组合,委托等技术和思想,有效 ...

  8. 深入理解javascript中的立即执行函数(function(){…})()

    投稿:junjie 字体:[增加 减小] 类型:转载 时间:2014-06-12 我要评论 这篇文章主要介绍了深入理解javascript中的立即执行函数,立即执行函数也叫立即调用函数,通常它的写法是 ...

  9. js架构设计模式——理解javascript中的MVVM开发模式

    理解javascript中的MVVM开发模式 http://blog.csdn.net/slalx/article/details/7856769 MVVM的全称是Model View ViewMod ...

  10. 全面理解Javascript中Promise

    全面理解Javascript中Promise 最近在学习Promise的时候,在网上收集了一些资料,发现很多的知识点不够系统,所以小编特意为大家整理了一些自认为 比较好的文章,供大家更好地学习js中非 ...

随机推荐

  1. RedHat Linux RHEL6配置本地YUM源

    YUM是Yellow dog Updater Modified的简称,起初是由yellow dog这一发行版的开发者Terra Soft研发,用python写成,那时还叫做yup(yellow dog ...

  2. asp.net mvc 之旅—— 第三站 路由模板中强大的自定义IRouteConstraint约束

    我们在写mvc的时候,经常会配置各种url模板,比如controller,action,id 组合模式,其实呢,我们还可以对这三个参数进行单独的配置,采用的方式自然 就是MapRoute中的const ...

  3. 初探ansible安装

    一.ansible介绍常用的自动化运维工具 Puppet —基于 Ruby 开发,采用 C/S 架构,扩展性强,基于 SSL,远程命令执行相对较弱SaltStack —基于 Python 开发,采用 ...

  4. ORA-01033因误删表空间文件导致的解决方案

    该类问题通常是由于表空间操作不当引起的.解决方法: SQL*Plus无法连接,显示以下错误:ORA-01033:ORACLE initialization or shutdown in progres ...

  5. XCode6 开发本地化应用

    使用 XCode 6 开发本地化时,第一步,不能忘记,否则在添加本地化文件时,可能会找不到简体中文. 此外,如果使用 NSLocalizedString(@"xxx", nil) ...

  6. java操作hdfs实例

    环境:window7+eclipse+vmware虚拟机+搭建好的hadoop环境(master.slave01.slave02) 内容:主要是在windows环境下,利用eclipse如何来操作hd ...

  7. Microsoft Azure Point to Site VPN替代方案

    Microsoft Azure提供了Point to Site VPN,但有时候这并不能满足我们的需求,例如:Point to Site VPN是SSTP VPN,只能支持Window客户端拨入,而且 ...

  8. 一些常用的String方法 C#

    String Reference: https://msdn.microsoft.com/en-us/library/system.string(v=vs.110).aspx Method Strin ...

  9. 第11章 Java异常与异常处理

    1.Java异常简介 1.什么是异常异常出现的时候代码会无法正常运行下去,会产生各种问题2.捕捉异常的作用提早发现异常,方便查找问题,并给出解决方法3.Java中的异常1.Java中所有不正常的类都是 ...

  10. 第1章 重构,第一个案例(2):分解并重组statement函数

    2. 分解并重组statement (1)提炼switch语句到独立函数(amountFor)和注意事项. ①先找出函数内的局部变量和参数:each和thisAmount,前者在switch语句内未被 ...