this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁, 实际上this的最终指向的是那个调用它的对象;
1.函数调用模式
当作函数调用,这时函数内的this指向全局对象(大对数情况下是window)
function a(){
var num= 233;
console.log(this.num); //undefined
console.log(this); //Window
}
a();
按照我们上面说的this最终指向的是调用它的对象,
这里的函数a实际是被Window对象所点出来的,
相当于window.a();
a() 是 一个函数也可以说是方法 ,那方法肯定是由对象来调用的。
所以当执行 a(); 时 就有一个隐式对象调用了a() ,这个隐式对象就是 window;
2.方法调用模式
当一个函数是一个对象的属性时,我们称它为该对象的一个方法,当一个方法被调用时,this指向该对象;
var o = {
t:"test",
fn:function(){
console.log(this.t); //test
}
}
o.fn();
这里的this指向的是对象o,因为调用这个fn是通过o.fn()执行的,那自然指向就是对象o,
这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁;
如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象;
var o = {
a:10,
b:{ // a:12,
fn:function(){
console.log(this.a); //undefined
}
}
}
o.b.fn();//尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,
不管这个对象中有没有this要的东西
还有一种比较特殊的情况:
var o = {
a:10,
b:{
a:12,
fn:function(){
console.log(this.a); //undefined
console.log(this); //window
}
}
}
var j = o.b.fn;
j();
这里this指向的是window,this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的;
虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window;
3.构造器调用模式 使用new调用的函数称为构造器函数,此时的this指向该构造器函数实例出来的对象;
function Fn(){
this.user = "test";
}
var a = new Fn();
console.log(a.user); //test
这个this指向对象a,这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a;
这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行, 而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象Fn中会有user, 因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。 除了上面的这些以外,还可以自行改变this的指向,用JavaScript中call,apply,bind方法更改this的指向。 一个小问题当this碰到return时
function fn()
{
this.user = 'test';
return {};
}
var a = new fn;
console.log(a.user); //undefined
再看一个
function fn()
{
this.user = 'test';
return function(){};
}
var a = new fn;
console.log(a.user); //undefined
再来
function fn()
{
this.user = 'test';
return 1;
}
var a = new fn;
console.log(a.user); //test
function fn()
{
this.user = 'test';
return undefined;
}
var a = new fn;
console.log(a.user); //test
什么意思呢? 如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。
function fn()
{
this.user = 'test';
return undefined;
}
var a = new fn;
console.log(a); //fn {user: "test"}
还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。
function fn()
{
this.user = 'test';
return null;
}
var a = new fn;
console.log(a.user); //test
4.apply/call调用模式以及bind
apply、call、bind方法可以让我们设定调用者中的this指向谁
function showValue(){
console.log(this.value);
}
var obj={
value:4
}
showValue.call(obj)//输出4,this指向了obj对象
call():
var a = {
user:"test",
fn:function(){
console.log(this.user); //test
}
}
var b = a.fn;
b.call(a);
通过在call方法,给第一个参数添加要把b添加到哪个环境中,简单来说,this就会指向那个对象,这里指向a ;
apply();
apply方法和call方法有些相似,它也可以改变this的指向;
var a = {
user:"test",
fn:function(){
console.log(this.user); //test
}
}
var b = a.fn;
b.apply(a);
//注意如果call和apply的第一个参数写的是null,那么this指向的是window对象
5.箭头函数中调用: es6里面this指向固定化,始终指向外部对象,因为箭头函数没有this,因此它自身不能进行new实例化, 同时也不能使用call, apply, bind等方法来改变this的指向;
function Timer() {
this.seconds = 0;
setInterval( () => this.seconds ++, 1000);
}
var timer = new Timer();
setTimeout( () => console.log(timer.seconds), 3100);
// 3
在构造函数内部的setInterval()内的回调函数, this始终指向实例化的对象, 并获取实例化对象的seconds的属性, 每1s这个属性的值都会增加1。
否则最后在3s后执行setTimeOut()函数执行后输出的是0;
6.Eval函数
该函数执行的时候,this绑定到当前作用域的对象上
var name="XL";
var person={
name:"xl",
showName:function(){
eval("console.log(this.name)");
}
}
person.showName(); //输出 "xl"
var a=person.showName;
a(); //输出 "XL"
如果在严格模式的情况下执行纯粹的函数调用,那么这里的的 this 并不会指向全局,而是 undefined,这样的做法是为了消除 js 中一些不严谨的行为;
'use strict';
function test() {
console.log(this);
};
test();
// undefined