一直感觉javascript
中的this
是一个大坑,虽然一直都有注意,一直都有研究,但是总是会忘记。在这里,总结一下一些简单的规律
不考虑箭头函数的情况下
下面的所有的都是不考虑箭头函数的情况下,因为箭头函数和普通的差别很大
直接调用的都是window
除非是bind
绑定过的,其他情况下,直接调用的方法的this
都是window
。所谓的直接调用,就是直接以method()
的形式调用,没有call
, apply
, new
看几种情况:
function foo(){
return this;
}
foo(); // window
var obj = {
foo: function(){ return this; }
}
var foo = obj.foo;
foo(); // window
function Foo(){
this.foo = function(){
console.log(this);
}
var foo = this.foo;
foo(); // window
}
new Foo();
谁调用,谁是this
除非是bind
绑定过的,一般情况下,谁调用这个方法,那么内部的this
就指向这个对象。也就是说obj.method()
,那么就指向obj
。obj.foo.method()
,那么就指向obj.foo
看几个例子:
var obj = {
foo: function(){ return this; }
}
obj.foo(); // obj调用,所以结果是obj
function foo(){ return this };
var obj = {};
obj.foo = foo;
obj.foo(); // obj调用,所以结果是obj
var obj = {
bar: function(){ return this; },
foo: function(){
return this.bar();
}
}
obj.foo(); // 在foo中, this是obj, 而this调用的bar, 所以返回的是obj
var obj = {
bar: {
foo: function(){ return this }
}
}
obj.bar.foo(); // obj.bar调用的foo,所以返回的结果是bar
function foo(){
this.bar = function(){ return this }
return this.bar();
}
foo(); // 由于foo中的this是window, 所以this.bar()返回的是window
function Foo(){
this.foo = function(){ console.log(this); }
this.foo();
}
var object = new Foo(); // 由于this.foo中的this是object,所以this是object
new会生成一个新的this
所有情况下,(箭头函数不能使用new
关键字),使用了new
以后,会把内部的this
指向新生成的对象。
除去bind的情况下,prototype
中的this
也指向新生成的对象
function Foo(){
console.log(this); // this指向新生成的对象,object
}
var object = new Foo();
function Foo(){
this.foo = function(){ return this === object; }
}
var object = new Foo();
object.foo(); // 输出true
function Foo(){}
Foo.prototype.foo = function(){ return this === object; }
var object = new Foo();
object.foo(); // 输出true
call, apply是谁,this就是谁
除非是bind的情况,call
, apply
是谁,那么内部的this
就是谁。
注意:如果是基本类型,那么javascript
会把基本类型转换成Object
的形式
也是看例子:
function foo(){ return this; }
foo.call("a"); // String
typeof foo.call("a"); // object
var obj = {
foo : function(){ return this; }
}
obj.foo.call(1); // Number
typeof obj.foo.call(1); // object
function Foo(){
this.foo = function(){ return this; }
}
var object = new Foo();
object.foo.call(1); // Number
bind是谁,this就是谁
除了new
这一种特殊情况,bind
的对象是谁,那么this
也就是谁。即使call
, apply
也没有权利改变。
注意:如果是基本类型,那么javascript
会把基本类型转换成Object
的形式
function foo() { return this; }
foo = foo.bind(1);
foo(); // Number
typeof foo(); // object
function foo() { return this; }
foo = foo.bind(1);
foo.call("a"); // Number 1
function Foo() { return this; }
Foo.prototype.foo = (function(){ return this; }).bind(1);
var object = new Foo();
object.foo(); // Number
特殊情况new
这个关键词可以改变方法内部的this
,使他指向新生成的对象
function Foo(){ this.foo = function(){ console.log(this === obj) } }
Foo = Foo.bind(1);
var obj = new Foo();
obj.foo(); // 输入true
箭头函数
箭头函数的"this"
是根据定义环境的this
来定的,也就是说定义的函数周围的this
是什么,它的"this"
就是什么。(注意我在this
上加了引号,是因为这个this
并不是真的箭头函数的this
)
而且不会被bind
, call
, apply
所改变
var foo = ()=>{ return this };
foo() // window
var obj = { foo: ()=>this }
obj.foo(); // 由于定义的时候,周围的环境是window,所以返回window
var obj = {
foo(){
var bar= ()=>{ return this };
return bar();
}
}
obj.foo(); // 由于定义bar的时候,周围环境是obj,所以返回obj
var foo = obj.foo;
foo(); // 同理,这里是window
var foo = ()=>{ return this };
foo = foo.bind(1);
foo(); // window
foo.call(1); // window
foo.apply(1); // window
function Foo(){
// 箭头函数
var a = ()=>{
console.log(this === object); // true
}
// 对比普通函数
var b = function(){
console.log(this === window); // true
}
this.foo = function(){
a(); b();
}
}
var object = new Foo();
object.foo();
function Foo(){}
// window
Foo.prototype.foo = ()=>{ return this }
// window
var object = new Foo();
object.foo(); // 由于定义foo的时候,周围环境是window,所以这里是window
小结
之前在上面写的都是记忆方法,方便记忆,但是并没有涉及到原理,这里大概点几点:
bind
以后,即使再bind
, apply
, call
也不会改变this
的值
其实可以从bind
的简单实现看出来:
Function.prototype.bind = Function.prototype.bind || function(context, ...args){
var func = this;
return function(...currentArgs){
return func.apply(context, args.concat(currentArgs));
}
}
所以,从这里看出来,bind
以后,返回了一个新的function
,所以即使以后再对返回的方法进行bind
, apply
, call
,也只是对新的function
操作,并不影响func.apply(context...)
中的context
值。但是可以影响后面的参数值。
关于bind
方法的介绍,今天看到颜海镜、颜大的文档,感觉对bind
的了解加深一步,附上链接
关于箭头函数的this
根据MDN的文档,箭头函数是不会生成自己的this
的(还有arguments)。所以我才给上面的this
加上双引号。而且由于它本身并没有this
,所以才不会被apply
,bind
, call
所改变。
那么在箭头函数中调用的this
是怎么来定的呢?
下面来自vajoy
的一篇译文
虽然箭头函数没有一个自己的
this
,但当你在内部使用了this
的时候,他会指向最近一层作用域的this
function foo(){
return ()=>{
return ()=>{
return ()=>{
console.log("id:", this.id);
}
}
}
}
foo.call({id:42})()()(); // id:42
这里只有一次this
的绑定,也就是foo()
的时候.
这些连接内嵌的函数们都没有生命他们自己的
this
,所以this.id
的引用会简单地顺着作用域链查找,一直查找到foo()
函数,他是第一处能找到一个确切存在的this
的地方。
由于只是我根据经验和资料自己总结的,所以不知道是否有疏忽或者遗漏,如果有问题的地方,欢迎提出。谢谢
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。