Fork me on GitHub

JavaScript中的this引用

基本介绍

  • JavaScript函数有4种调用模式,分别是:函数直接执行模式对象方法的调用模式构造器的调用模式call/apply调用模式
  • 函数调用每种方式的不同在于this值的初始化
  • 一般而言,在JavaScript中,this指向调用当前函数的对象箭头函数的this定义函数的时候绑定)。
  • this是保留关键字,不能修改this的值。

this

  • this是函数内部的一个特殊对象(或this引用),它引用的是函数据以执行的环境对象
  • this是JavaScript的一个关键字,随着函数使用场合不同,this的值会发生变化。但总有一个原则,即this指的是调用当前函数的对象
    • JavaScript是动态语言,this关键字在执行的时候才能确定其值
    • this永远指向调用者,即对“调用对象”的引用。简单点说,this指向调用当前函数的所属对象
    • 根据函数调用方式的不同,this可以指向全局对象,当前对象,或其他任意对象。
  • this对象(引用)的使用情况可总结为:
    • 全局函数调用
    • 构造函数调用
    • 对象方法的调用
    • 通过apply或call方法调用
    • 原型链中的this
    • 闭包中的this
    • 内嵌在HTML元素中的脚本段
全局函数调用
  • 全局函数中的this指向全局对象window。(函数调用模式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var message = "this in window"; // 这一句写在函数外面和里面是一样效果
    function func() {
    if(this == window){
    alert("this == window");
    alert(message);
    this.methodA = function() {
    alert("I'm a function");
    }
    }
    }
    func(); // 如果不调用func方法,则里面定义的属性或方法会取不到
    methodA();
构造函数调用
  • 使用new的方式实例化一个对象,this会指向通过构造函数生成的对象。(构造器调用模式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Func() {
    if (this == window) {
    alert("this == window");
    }
    else {
    alert("this != window");
    }
    this.fieldA = "I'm a field";
    alert(this);
    }
    var obj = new Func();
    alert(obj.fieldA); // this指向的是对象obj
对象方法的调用
  • 对象方法的调用,this指向当前对象。任何函数,只要该函数被当做一个对象的方法使用或赋值时,该函数内部的this都是对该对象本身的引用。也可理解为this写在一个普通对象中,this指向的就是对象本身。(方法调用模式)
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var obj = {
    x: 3,
    doit: function(){
    if(this == window){
    alert("this == window");
    }else{
    alert("method is called: " + this.x);
    }
    }
    };
    obj.doit(); //this指向的是对象obj
通过apply或call方法调用
  • 通过applycall方法改变this的指向,this指向传入的对象。
  • applycall方法可以用来代替另一个对象调用一个方法。
  • applycall方法可将一个函数的对象上下文从初始的上下文改变为由thisObj指定的新对象。
  • 如果没有提供thisObj参数,那么全局对象被用作thisObj
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var obj = {
    x: 3,
    doit: function(){
    alert("method is called: " + this.x);
    }
    };
    var obj2 = {x: 4};
    obj.doit(); // 3, this指向obj
    obj.doit.apply(obj2); // 4, this指向obj2
    obj.doit.call(obj2); // 4, this指向obj2
原型链中的this
  • 原型对象及构造函数中的this指向新创建的实例对象
  • 使用prototype扩展方法可以使用this获取到源对象的实例,私有字段无法通过原型链获取。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function Func() {
    this.fieldA = "I'm a field";
    var privateFieldA = "I'm a var";// 私有属性
    }
    Func.prototype = {// prototype扩展方法可以获取到Func对象的实例
    ExtendMethod: function(str) {
    alert(str + " :" + this.fieldA);
    alert(privateFieldA); // 出错,私有字段无法通过原型链获取。
    }
    };
    var obj = new Func();
    obj.ExtendMethod("From prototype"); // 此时构造函数及原型链中的this指向对象obj
闭包中的this
  • 闭包:写在function中的function,this指向全局对象window
对象中的闭包
1
2
3
4
5
6
7
8
9
10
var name = "The window";
var obj = {
name: "My Object",
getNameFunc: function(){
return function(){
return this.name;
}
}
};
alert(obj.getNameFunc()()); // The window
  • 可见,闭包中的this指向全局对象window,只能取到全局对象的属性。若要访问对象内部的属性(外部函数的变量),则要把外部函数的this对象保存为一个闭包能访问的变量(that)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    var name = "The window";
    var obj = {
    name: "My Object",
    getNameFunc: function(){
    var that = this;
    return function(){
    return that.name;
    }
    }
    };
    alert(obj.getNameFunc()()); //My object
  • 不管是直接引用function,还是实例化一个function,其返回的闭包函数里的this都是指向window

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function a() {
    alert(this == window);
    var that = this;
    var func = function() {
    alert(this == window);
    alert(that);
    };
    return func;
    }
    var b = a();
    b(); //true, true, [object Window]
    var c = new a();
    c(); //false, true, [object object]
内嵌在HTML元素中的脚本段
  • 内嵌在HTML元素中的脚本段,this指向元素本身
    1
    2
    3
    4
    5
    6
    <div onclick="test(this)" id="div">Click Me</div>
    <script type="text/javascript">
    function test(obj) {
    alert(obj); //[object HTMLDivElement]
    }
    </script>

js函数的四种调用方式

函数直接执行模式
  • 此时this是全局的,即this指向window。
    1
    2
    3
    4
    var c = function(){
    alert(this == window)
    }
    c() // true
对象方法的调用模式
1
2
3
4
5
6
7
var myObj = {
value: 2,
inc: function(num){
alert(this.value + num);
}
}
myobject.inc(1); // 结果3,因为this指向myObj
  • 注意:内部匿名函数不属于当前对象的函数,因此this指向了全局对象window
构造函数调用模式
  • new关键字来新建一个函数对象的调用,this指向被绑定到构造函数的实例上
    1
    2
    3
    4
    5
    6
    7
    8
    var fn = function (status){
    this.status = status;
    }
    fn.prototype.get_status = function(){
    return this.status;
    }
    var test = new fn('my status');
    alert(test.get_status);// my status, this指向test
apply/call调用模式
  • 通过applycall可以重新定义函数的执行环境,即this的指向。
  • applycall一样的用法,只不过apply第二个参数用数组进行传递。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    function MyObject(name){
    this.name = name ||'MyObject';
    this.value = 0;
    this.increment = function(num){
    this.value += typeof(num) === 'number' ? num : 0;
    };
    this.toString = function(){
    return '[Object:'+this.name+' {value:'+this.value+'}]';
    };
    this.target = this;
    }
    function getInfo(){
    return this.toString();
    }
    var myObj = new MyObject();
    alert(getInfo.apply(myObj)); // [Object:MyObject {value:0}], this指向myObj
    alert(getInfo.apply(window)); // [object Window], this指向window
------ 本文结束 ------