js中的this

Global context

全局的this
In the global execution context (outside of any function), this refers to the global object, whether in strict mode or not.

// In web browsers, the window object is also the global object:
console.log(this === window); // true

console.log(this.document === document); // true

documentwindow的一个对象属性

//非函数内直接使用 var 声明的变量默认为全局变量,且默认挂在 window 上作为属性。
var a = 37;
console.log(window.a); // 37

延伸

var x = 10;

function func() {
  return this.x
}

var obj = {
  x: 20,
  fn: function() {
    return this.x
  }
}

var fn = obj.fn

console.log(func()) // 10

console.log(obj.fn()) // 20

console.log(fn()) // 10

func()和fn()最终输出的都是全局的 10。永远记住这一点:判断 this 指向谁,看执行时而非定义时,只要函数(function)没有绑定在对象上调用,它的 this 就是 window。

Function context

Simple call

一般函数的 this
Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object:

function f1(){
  return this;
}
// In a browser:
console.log( f1() === window ); //true, the window is the global object in browsers

// In Node:
f1() === global

一般函数的 this 也指向 window,在 nodeJS 中为 global object

in strict mode, if this was not defined by the execution context, it remains undefined.

function f2 () {
    "use strict";//使用严格模式
    return this;
}
console.log( f1() === undefined );//true

严格模式中,函数的 this 为 undefined,因为严格模式禁止this关键字指向全局对象;对于js“严格模式”具体可以看阮一峰先生的Javascript 严格模式详解

As an object method

作为对象的方法调用

var o = {
  prop: 37,
  f: function() {
    console.log( this === o );  // true
    return this.prop;
  }
};

console.log(o.f()); // logs 37

当函数作为对象内的一个方法被调用的时候,this指向拥有该方法的对象。

var o = {prop: 37};

function independent() {
  return this.prop;
}

o.f = independent;

console.log(o.f()); // logs 37
o.b = {g: independent, prop: 42};
console.log(o.b.g()); // logs 42

As a function call

作为函数调用

function makeNoSense(x) {
    this.x = x;
}
makeNoSense(5);
x;// x 已经成为一个值为 5 的全局变量

此时 this 绑定到全局对象。在浏览器中,window 就是该全局对象。比如下面的例子:函数被调用时,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);   //this 绑定到全局
        moveY(y);
    }
};
point.moveTo(1, 1);  
console.log(point.x) //0
console.log(point.x) //0
console.log(x)       //1
console.log(y)       //1

that方法解决绑定到point对象上

As Internal function

内部函数

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		var sayhello = function(sth) {
			console.log(this.name + " says " + sth);
		};
		sayhello(sth);
	}
}
person.hello("hello world");//clever coder says hello world

此时内部函数中的this指向全局对象。

绑定到外层函数对象person上:一般的处理方式是将this作为变量保存下来,一般约定为that或者self。

var name = "clever coder";
var person = {
	name : "foocoder",
	hello : function(sth){
		var that = this;
		var sayhello = function(sth) {
			console.log(that.name + " says " + sth);
		};
		sayhello(sth);
	}
}
person.hello("hello world");//foocoder says hello world

this on the object’s prototype chain

对象原型链上的this

var o = {
    f: function() {
        return this.a + this.b;
    }
};
var p = Object.create(o);
p.a = 1;
p.b = 2;
console.log(p.f()); //3

通过 var p = Object.create(o) 创建的对象,p 是基于原型 o 创建出的对象。

p 的原型是 o,调用 f() 的时候是调用了 o 上的方法 f(),这里面的 this 是可以指向当前对象的,即对象 p。

this with a getter or setter

get/set 方法与 this

function sum(){
  return this.a + this.b + this.c;
}

var o = {
  a: 1,
  b: 2,
  c: 3,
  get average(){
    return (this.a + this.b + this.c) / 3;
  }
};

Object.defineProperty(o, 'sum', {
    get: sum, 
    enumerable:true, 
    configurable:true
});

console.log(o.average, o.sum); //  2, 6

As a constructor

作为构造函数

function C(){
  this.a = 37;
}

var o = new C();
console.log(o.a); // 37

没有返回值或者返回为基本类型时,默认将 this 返回。

function C2(){
  this.a = 37;
  return {a:38};
}

o = new C2();
console.log(o.a); // 38

因为返回了对象,将这个对象作为返回值

call and apply

function add(c, d) {
    return this.a + this.b + c + d;
}
var o = {
    a: 1,
    b: 3
};
console.log( add.call(o, 5, 7) ); // 1 + 3 + 5 + 7 = 16
console.log( add.apply(o, [10, 20]) ); // 1 + 3 + 10 + 20 = 34
function bar() {
    console.log(Object.prototype.toString.call(this));
}
bar.call(7); // "[object Number]"
bar.call("7");//[object String]
bar.call(true);//[object Boolean]
bar.call(); //[object Window]
bar.call(this); //[object Window]

The bind method

1
2
3
4
5
6
7
8
9
10
11
function f() {
  return this.a;
}
o = {
  a: "hello"
}
var g = f.bind(o);

console.log( f.call(o) );   // hello
console.log( f.bind(o) );   //function f(){... }
console.log( f.bind(o)() ); // hello
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function f() {
  return this.a;
}
o = {
  a: "hello"
}
var g = f.bind(o);

var obj = {
  a: 37,
  f: f,
  g: g
}
console.log(obj.f(), obj.g()); //37 hello

As a DOM event handler

this === e.currentTarget

1
<div id="demo">click</div>
var demo = document.getElementById("demo");

function f(e){
		console.log(this);               // <div id="demo">click</div>
		console.log(e.target);           // <div id="demo">click</div>
		console.log(e.currentTarget);    // <div id="demo">click</div>
		console.log(this === e.target);  // true,or false
    console.log(this === e.currentTarget);   // true
}
demo.addEventListener("click",f,false);

In an in–line event handler

1
2
3
4
5
<div id="demo" onclick="console.log(this)">click</div>
<!-- <div id="demo" onclick="console.log(this)">click</div>  -->

<div id="demo" onclick="console.log( (function(){ return this })() )">click2</div>
<!-- window对象 -->

Arrow functions

var book = {
  author: 'John Resig',
  init: function() {
    document.onclick = ev => {
      alert(this.author) ; // 这里的 this 不是 document 了
    }
  }
};
book.init()

总结:

1.当函数作为对象的方法调用时,this指向该对象。

2.当函数作为淡出函数调用时,this指向全局对象(严格模式时,为undefined)

3.构造函数中的this指向新创建的对象

4.嵌套函数中的this不会继承上层函数的this,如果需要,可以用一个变量保存上层函数的this。

番外篇一些关于this的笔试题

var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
    return function(){
      return this.name;
    };
  }
};

var obj = object.getNameFunc();

console.log(object.getNameFunc()());  // The Window

console.log(obj());  // The Window
var name = "The Window";
var object = {
  name : "My Object",
  getNameFunc : function(){
	     var that = this;
    return function(){
      return that.name;
    };
  }
};

var obj = object.getNameFunc();

console.log(object.getNameFunc()());  // My Object

console.log(obj());  // My Object

更多-more