首先需要理解:
1.this的指向在函数定义的时候并不能确定this的指向
2.this的最终指向是那个调用它的直接对象(注意两个词 :1.最终指向 2. 直接对象)
列子1
function a () {
var user = '赵老二';
console.log(this.user)//undefined
console.log(this)//window
}
a() //a()==window.a()
按照上面手的this指向调用它的直接对象,那么这个调用的对象为window,所以this指向window
列子2
let a = {
user:'赵老二',
fn: function () {
console.log(this.user)//赵老二
console.log(this)//{user: "赵老二", fn: ƒ}对象
}
}
a.fn()
fn()的直接调用对象是a,所有this指向a,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。
列子3
let a = {
user:'赵老二',
fn: function () {
console.log(this.user)//undefined
console.log(this)//window
}
}
let b=a.fn
b()
这里this指向的是window,是不是有些蒙了?其实是因为你没有理解一句话,这句话同样至关重要。
this永远指向最后调用它的那个对象,这里b=a.fn并没有执行,只是一个赋值的过程,b()才进行调用,并且在window下直接调用的所以this指向window
列子5
var o = {
a:10,
b:{
fn:function(){
console.log(this.a); //undefined
console.log(this);//{fn: ƒ}
}
}
}
o.b.fn();
这里要记住一句话,this指向的永远是调用它的直接对象,所以上面的this指向的是b对象
再次说明:this指向的是最终调用该方法的直接对象;
构造函数版的this
function Fn(){
this.user = "赵老二";
}
var a = new Fn();
console.log(a.user); //赵老二
这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,为什么我说a是对象,因为用了new关键字就是创建一个对象实例,理解这句话可以想想我们的例子3,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象a中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。
添加手动实现new的过程
function Fn() {
this.user ='赵老二';
}
function newfn(fn) {
let obj = {};
//此外因为 shift 会修改原数组,所以 arguments 会被去除第一个参数
const Constructor = [].shift.call(arguments)
// 将obj的原型指向构造函数的原型对象,这样obj就可以访问构造函数原型上的属性
obj.__proto__ = Constructor.prototype
// 将构造函数的this指向obj,这样obj就可以访问到构造函数中的属性
Constructor.apply(obj, arguments);
return obj;
}
newfn(Fn) //Fn{user:'赵老二'}
更新一个小问题当this碰到return时
function fn()
{
this.user = '赵老二';
return {};
}
var a = new fn;
console.log(a.user); //undefined
function fn()
{
this.user = '赵老二';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
再来
function fn()
{
this.user = '赵老二';
return 1;
}
var a = new fn;
console.log(a.user); //赵老二
function fn()
{
this.user = '赵老二';
return undefined;
}
var a = new fn;
console.log(a.user); //赵老二