扑朔迷离的 this关键字

在Java,C#等面向对象的语言中,this的含义是明确且具体的,固定指向运行时的当前对象。而由于Javascript的动态性(边解释边执行),this的指向在运行时才能确定,跟定义在哪儿无关。

this总是返回一个对象,就是属性或方法 当前 所属的对象。一般来讲,就是“.”前的那个对象(个人认为这种说法是非常容易误导人的)

var name = ‘张三‘;
var obj = {
    name: ‘李四‘,
    introduce: function(){
        console.log(‘my name is‘ + this.name);
    }
};
obj.introduce();
var f1 = obj.introduce;
f1();

在这个例子中,obj.introduce() "."左边是obj,所以this指向obj这个对象。introduce方法里面的this.name沿着作用域链往上找就是“李四”;

我们都知道函数后面带括号表示执行,不带括号就是把函数指针赋值给变量,但不执行函数,所以f1其实就是指代 function(){console.log(‘my name is‘ + this.name);},不妨可以console出来验证一下。f1()是在全局window对象中,所以这里的f1()其实就是window.f1(),也就是说"f1()"打印输出的应该是全局变量“张三”

关于刚才提到的f1函数,我们可以进一步验证下

function f1(){
    return this;
};
console.log(f1() === window);

在这里,可以得出一个结论,如果一个函数运行在全局对象中,那么,this就是指向顶层对象,在浏览器中即为window对象。

基于前面的分析,我们把上例稍微改变一下

var obj = {
    name: ‘李四‘,
    describe: function () {
        console.log( ‘my name is‘+ this.name);
    }
};

var obj2 = {
    name: ‘张三‘
};

obj2.describe = obj.describe;
obj2.describe();

this指向obj对象,这点已经分析过了。这个例子中“obj2.describe = obj.describe;”说白了就是给obj2对象添加一个describe方法,this同样指向当前所在的对象,所以输入的就是“张三”,obj2对象实际变成了

obj2 = {
    name: ‘张三‘,
    describe: function () {
        console.log( ‘my name is‘+ this.name);
    }
};

this的使用场合

1、全局环境         this--->指向全局对象 window

全局中的this就是顶层对象window

这个例子说明,不管this是不是在函数内部,只要是在全局环境下运行,this都指向window

这里需要稍微提示下,在严格模式下,全局中的this就不再是window对象了,而是undefined

2、构造函数       this--->指向新对象

构造函数中的this,指向生成的新对象

var a = 3; //全局变量a
function Test(){
    this.a = 5;  //对象属性a
}
var obj = new Test();
console.log(obj.a);

上面代码定义了一个构造函数Test,同时创建了Test的实例对象obj,我们知道通过new操作符创建构造函数的新实例对象,主要经历了4个步骤:

(1)、创建一个新对象

(2)、将构造函数的作用域赋给新对象(因此this就指向了这个新对象)

(3)、执行构造函数中的代码(为这个新对象添加属性)

(4)、返回新对象

根据这4个步骤,obj对象其实就是

Test {a: 5}

所以,很显然obj.a打印出来的a就是5,而不是3了

再来看一个例子:

var Obj = function (p) {
    this.p = p;
};

Obj.prototype.m = function() {
    return this.p;
};
var o = new Obj(‘Hello World!‘);

o.p; 
o.m();

首先创建了一个构造函数Obj,给Obj的原型对象添加了一个方法m,m同样返回属性p,然后创建一个Obj的实例对象o,基于前面的分析,最终输出的就应该是两个‘Hello World!‘了

3、对象的方法         this--->指向当前这个对象

当A对象的方法被赋予给B对象,该方法中的this就会从指向A对象变成了指向B对象。所以需要特别注意,将某个对象的方法赋值给另一个对象,会改变this的指向

先来验证第一句话,作为对象的方法被调用,this指向当前这个对象

由此说明,obj.foo方法执行时,它内部的this指向了当前对象obj。先来看一个例子:

function test(){
    console.log(this.a);
}
var a = 3; //声明一个全局变量a
var obj = {}; //创建一个对象obj
obj.a = 5;  //给obj添加一个属性a
obj.m = test;  //给obj添加一个方法m,并且把test指针指向了m
console.log(obj);
obj.m();

再来看一个例子:

var name = "sky";
var obj = {
    name:"zt",
    say:function(){
        console.log("I am "+this.name);
    }
}
obj.say();//I am zt
var fn = obj.say;
fn();//I am sky

obj.say()这个就不需要多说,在对象自己的方法里面,this指向当前的对象obj,所以是zt

把obj对象的say方法赋予给另一个fn函数,所以this会从obj指向fn,而fn运行在全局环境中,所以输出的全局变量sky

4、内部函数(匿名函数)   匿名函数的执行环境具有全局性,this对象通常指向window

var name = ‘Window‘;
var obj = {
    name: ‘My Object‘,
    getName: function(){
        return function(){
            return this.name;
        }
    }
};
console.log(obj.getName()()); //Window

按照上面的说法,似乎可以很快确认输出的是Window。我们不妨做下拆解,执行obj.getName(),得到的是一个匿名函数function(){return this.name;},此时,这个匿名函数运行在全局环境中,再次执行这个函数,里面的this自然就指向了全局Window

在定时器里面的this是否也是指向window呢?

var name = "sky";
var obj = {
    name:"zt",
    say:function(){
        setTimeout(function(){
            console.log("I am "+this.name);
        },3000);
    }
};
obj.say();

可以看到,执行say方法,其实就是一个一次性定时器,3s之后执行function(){console.log("I am"+this.name);},可能按照我们前面的说法“.”前的对象是obj,所以this指向obj,这个没错,但是,这是say方法里的this,定时器的代码是在全局作用域window对象中执行的,所以这里面的this指向window,当然严格模式下是undefined,所以最终输出的是全局的sky而不是obj对象里面的zt

从上面的两个例子中可以看到,getName和say两个方法中,内层函数中的this没有按预想的指向外层函数对象,而是指向全局对象window,那如果我们需要指向外层函数对象,怎么办呢?这里就需要用到我们常见的“留住this”

var name = "sky";
var obj = {
    name:"zt",
    say:function(){
        var that = this; //把this保存到一个变量中
        setTimeout(function(){
            console.log("I am "+that.name);
        },3000);
    }
};
obj.say(); //I am zt
var name = ‘Window‘;
var obj = {
    name: ‘My Object‘,
    getName: function(){
        var me = this; //this指向obj对象,我们把这个this放到一个变量中保存起来
        return function(){
            return me.name; //成功留住了this
        }
    }
};
console.log(obj.getName()()); //My Object

最后,再来看一个经典的面试题

var x=5,o={
    x:10,
    doit:function doit(){
        var x=20;
        setTimeout(
                function(){
                    console.log(this.x); //5
        }, 10);
    }
};
console.log(o.doit());//undfined
(function(){console.log(this.x)})();//5

参考上面的第4条,可以很容易得出结论 匿名函数 “function(){console.log(this.x)}”运行在全局window中,所以输出的两个5没有问题,关键是为什么o.doit()打印出来是undefined,原因很简单,doit方法没有return任何东西,它是没有返回值的。那如果给它加一个返回值呢?

var x=5,o={
    x:10,
    doit:function doit(){
        var x=20;
        setTimeout(
                function(){
                    console.log(this.x); //5
        }, 10);
        return this.x; //用在对象的方法中,this指向当前的对象o
    }
};
console.log(o.doit());//10  返回的是"return this.x;"
(function(){console.log(this.x)})();//5
时间: 2024-08-05 10:54:19

扑朔迷离的 this关键字的相关文章

轻松搞定this绑定方法 call apply bind

先来看一个例子 var obj = {}; //创建一个对象 obj.name = "James";  //给对象添加一个属性 obj.say = function(){  //给对象添加一个方法     console.log('My name is' + this.name); }; obj.say(); //this指向obj,所以输出"My name is James" var fn = obj.say; fn(); //this指向了window,全局中没

深入解析JavaScript中的this关键字

如果问初学者js中什么东西比较难懂,很多回答会是this关键字.this在不同场景下所指向的对象不同,这就有一种扑朔迷离的感觉,放佛魔法一般神秘:this到底是什么?这里有四种绑定规则. 1. 默认绑定 默认绑定是无法应用其他调用规则时的绑定方式,看如下代码: 1 var a = 1; 2 3 function foo(){ 4 console.log(this.a); 5 } 6 7 foo(); // 1 1 "use strict"; 2 3 var a = 1; 4 5 fun

JAVA synchronized关键字锁机制(中)

synchronized 锁机制简单的用法,高效的执行效率使成为解决线程安全的首选. 下面总结其特性以及使用技巧,加深对其理解. 特性: 1. Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码.       2. 当一个线程同时访问object的一个synchronized(this)同步代码块时,其它线程仍然可以访问非修饰的方法或代码块.       3. 当多个线程同时访问object的synchronized(this)同步代码

Java 中几个重要的关键字

Java中的关键字特别多,大致如下: 访问控制 private protected public 类,方法和变量修饰符 abstract class extends final implements interface native new static strictfp synchronized transient volatile 程序控制 break continue return do while if else for instanceof switch case default 异常

RobotFramework自动化测试框架的基础关键字(五)

1.1.1        Run Keyword If判断的使用 Run Keyword If是一个常用的用来做逻辑判断的关键字,意思是如果满足了某一个判断条件,然后就会执行关键字,我们对list3中放入0,1,2三个元素,然后遍历list3,判断当取到元素为0时,我们输出"男生". @{list3} Create List      0     1     2 :FOR       ${value} in    @{list3} Run Keyword If        '${va

this关键字的使用

* this关键字的使用: * 1.this:可以理解为:当前对象 或 当前正在创建的对象 * * 2.this可以用来调用:属性.方法.构造器 * * 3.this调用属性.方法 * 在方法中:我们可以在方法中通过"this.属性"或者"this.方法"的方法,表示调用当前对象的指定属性或方法.但是通常 * 情况下,我们都省略了"this.".但是如果方法的形参和当前对象的属性名相同的情况下,我们必须显式的使用"this.变量&quo

关键字和继承

1.关键字的使用 2.继承

【转】C++中的explicit关键字

在C++程序中很少有人去使用explicit关键字,不可否认,在平时的实践中确实很少能用的上.再说C++的功能强大,往往一个问题可以利用好几种C++特性去解决.但稍微留心一下就会发现现有的MFC库或者C++标准库中的相关类声明中explicit出现的频率是很高的.了解explicit关键字的功能及其使用对于我们阅读使用库是很有帮助的,而且在编写自己的代码时也可以尝试使用.既然C++语言提供这种特性,我想在有些时候这种特性将会非常有用. 按默认规定,只用传一个参数的构造函数也定义了一个隐式转换.举

就是要你懂Java中volatile关键字实现原理

原文地址http://www.cnblogs.com/xrq730/p/7048693.html,转载请注明出处,谢谢 前言 我们知道volatile关键字的作用是保证变量在多线程之间的可见性,它是java.util.concurrent包的核心,没有volatile就没有这么多的并发类给我们使用. 本文详细解读一下volatile关键字如何保证变量在多线程之间的可见性,在此之前,有必要讲解一下CPU缓存的相关知识,掌握这部分知识一定会让我们更好地理解volatile的原理,从而更好.更正确地地