this 原理
首先,要知道的是
this是指函数当前的运行环境(上下文)。
我们都知道 this 是函数运行时所在的环境,但我们不知道是函数的运行环境到底是怎么决定的。
var obj = {
fn:function(){
console.log(this.title);
},
title:"Hello"
}
var fn = obj.fn;
var title = "Hi";
obj.fn() //"Hello"
fn() //"Hi"
上面的例子中,obj.fn 和 fn调用的都是同一个函数,但结果却不一样,这就是我们上面说的 this 是根据运行时所在环境不同导致的,对于 obj.fn 来说,fn 是运行来 obj 环境的,所以this 指向 obj,对于 fn 来说是运行在全局的,因此 this 指向的是全局,也就是 window。
那为什么 obj.fn() 就是在 obj 环境运行的,而一旦 var fn = obj.fn 就变成全局环境了呢?下面让我们一点点揭开 this 的神秘面纱。
1. 内存的数据结构
javascript 之所有有 this,是和内存结构有关系的。
var obj = {fn:5}
以上代码,将一个对象赋值给变量 obj,在 javascript 的 引擎中会先在内存中,生成一个对象 { fn:5},然后在将这个对象的地址赋给变量 obj。

就是说,变量 obj 只是存了一个地址,如果要进行取读操作 obj.fn,那引擎是先从 obj 拿到内存地址,然后在从该地址读出原始对象,然后返回它的 fn 属性。
原始的对象以类似于字典结构的状态保存,每一个属性名都对应一个属性描述对象。拿上面的那个例子的 fn 属性来看

注意!fn 属性的值是保存在属性描述对象的 value 属性里面
2. 函数
属性值不是一个函数的时候很清晰,那如果属性的值是一个函数呢?
var obj = { fn: function(){}};
当对象的属性值是函数的时候,javascript 引擎会单独把函数保存在内存中,然后再将函数的地址赋值给 fn 属性的属性描述对象的 value 属性上。

由于函数是单独的一个值,所以它可以在不同的环境 ( 上下文 ) 中运行。
var fn = function(){
console.log(this.age);
};
var obj = {
fn: fn,
age: 5
};
var age = 10;
//单独运行时
fn(); //10
//在obj中运行时
obj.fn(); // 5
3. 环境变量
由于 javascript 允许函数体内,引用当前环境的其他变量,而变量是有当前的运行环境提供的,那么由于函数是可以在不同的运行环境中执行,那就需要一种机制,一种能够在函数体内部获得当前运行环境。so,这时 this 出现了,它的目的就是在函数体内部,指向函数当前的运行环境。
function fn (){
console.log(age); //由运行环境提供
}
var age= 10";
fn(); //10
以上代码中的 age 就由该函数运行时所在的环境提供。
再看,下面的例子
function fn(){
console.log(this.xx);
}
var xx = 10;
var obj = {
fn: fn,
xx: 100
}
//单独运行时
fn()//10
//在obj中运行时
obj.fn()//100
- 以上代码中,
this.xx指向运行时所在的环境的 xx。 - 当
fn()单独运行时,this.xx指向全局环境的 xx。 - 当
obj.fn()运行时,则this.xx指向的是obj环境的 xx。
现在,我们回到文章中最开始提出的问题,obj.fn() 是通过 obj 找到的 fn,所以就是在 obj 环境执行,一旦 var fn = obj.fn,则 变量 fn 就直接指向了函数本身,所以 fn() 就变成了全局环境执行。
注意!不要忘记,当对象里的属性名的值是一个函数的时候,这时,javascript 引擎就报函数单独保存在内存中,然后把函数地址给了 属性名的属性描述对象的value上。
this 使用
this 是 javascript 中的一个关键字。
它是在运行时,在函数体内自动生成的一个对象,因此只能在函数体内使用
下面让我们直截了当的来看下 this 的几种使用方式
1. 函数调用
函数的通常用法,这种属于全局调用,因此这时 this 就代表者全局对象
var x = 1;
function fn(){
console.log(x); // 变量 x,这时是全局的变量 x
}
fn(); //1
2. 匿名函数的使用
匿名函数执行时,this 代表者全局
var x = 1;
var fn = function(){
console.log(this.x);
}
fn(); // 1
//常用闭包式匿名函数
(function(){
console.log(this.x)
})() //1
3. 作为对象调用
当函数作为对象调用的时候,此时的 this 是这个上级对象
function fn(){
console.log(this.x); //this 指向 obj
}
var obj = {
x:1,
m:fn
}
obj.m(); // 1
4. 构造函数使用
当通过构造函数,生成一个新对象时,此时 this 是指这个新对象
function Fn(){
this.x = 1;
}
var x = 2;
var obj = new Fn();
obj.x // 1
5. apply / call 时调用
apply/call 是函数的一个方法,主要就是用来改成函数调用的,第一个参数就是要改变的对象,因此,this 就是指这第一个参数,如果第一个参数无,那 this 就代表者全局
var x = 1;
function fn(){
console.log(this.x);
}
var obj = {
x: 2,
m:fn
}
obj.m.apply(); // 1
更多详情请移步 阮一峰老师博文