js中的this
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
//非函数内直接使用 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