Javascript的this指向问题

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/betty13006159467/article/details/80669923

javascript中的this指向是在函数调用时确定的。

(1)、this指向全局对象window的情况

1、全局作用域中或普通函数中

//全局作用域
console.log(this); //非严格模式window,严格模式undefined
//普通函数
function bar(){
    console.log(this); //非严格模式window,严格模式undefined
}
bar(); //相当于bar.call(window)

2、 匿名函数和自执行函数

匿名函数的执行环境具有全局性,因此其this对象指向window,闭包中this指向window,可以将全局变量常驻内存。(javascript高级程序设计第2版148页)

//自执行函数
(function(){
    console.log(this); //window
})();
var name = "the window";
var object = {
    name:"My Object",
    getNameFunc:function(){
        return function(){ //这里形成一个闭包
            return this.name;  //this指向window
        }
    }
};
console.log(object.getNameFunc()());  //输出the window

3、嵌套函数和回调函数中
和变量不同,关键字this没有作用域的限制,嵌套的函数不会从调用它的函数中继承this;如果嵌套函数作为方法调用,其this的值指向调用它的对象;如果嵌套函数作为函数调用,其this值是全局对象(非严格模式)或undefined(严格模式下)。调用嵌套函数时this并不是指向调用外层函数的上下文。(javascript权威指南第6版171页)

var o={
       m:function(){
            var self=this;  //将this保存到变量self中
            console.log(this);  //this指向调用它的对象o
            f();
            function f(){   //定义一个嵌套函数f
                console.log(this); //非严格模式下,this指向window
                console.log(self); //self保存的是外层函数的this
                }
            }
        };
o.m();

(2)、函数作为对象的方法调用,this指向那个对象

var obj = {
    name:"123",
    getName:function(){
        console.log(this);//this指向obj
        console.log(this.name); //输出123
    }
};
obj.getName(); //相当于obj.getName.call(obj)

(3)、构造函数调用
1、若构造函数无return或return 一个原始值或null(即数字、字符串、布尔、undefined、null),this指向new出来的那个对象,返回值类型,有原型方法;

//无返回值的构造函数
function Super1(a){
        this.a = a; 
        //return 123; //返回原始值或null有同样的效果
}
//定义两个原型方法
Super1.prototype.sayHello=function(){
        console.log("Hello");
};
Super1.prototype.age = 18;

var newsup1 = new Super1(1);//实例化对象
console.log(newsup1); // Super1 { a=1,  age=18,  sayHello=function()}
console.log(newsup1.a); //1
console.log(newsup1.age); //18
newsup1.sayHello(); //Hello

2、若构造函数return 一个引用类型(即数组、函数、对象),this指向返回的那个引用类型,返回引用类型,没有原型方法;

//返回值为引用类型的构造函数
function Super2(a){
        this.a = a; 
        return {a:2}; //返回原始值或null有同样的效果
}
//定义两个原型方法,在这里没有用
Super2.prototype.sayHello=function(){
        console.log("Hello");
};
Super2.prototype.age = 18;

var newsup2 = new Super2(1);//实例化对象
console.log(newsup2); //  Object { a=2}
console.log(newsup2.a); //2
console.log(newsup2.age); //undefined
newsup2.sayHello(); //出错,TypeError: newsup2.sayHello is not a function

(4)、事件中this指向
W3C事件处理程序中,this指向触发这个事件的对象;但IE中,attachEvent中的this总是指向全局对象window,这是两者的主要区别。

(5)、综合应用

第一个例子

var o={
   a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this);
            console.log(this.a);
        }
    }
};
//(1)
o.b.fn(); //输出b和12

//(2)
var j=o.b.fn;
j(); //输出window和undefined

//(3)
var j=o.b;
j.fn(); //输出b和12

上例中(1)相当于o.b.fn.call(b),this永远指向的是最后调用它的对象,所以this指向b;
上例(2)相当于j.call(window),this指向window;
上例(3)相当于j.fn.call(j),实则j.fn.call(o.b),this指向最后调用它的对象b。

第2个例子

var name = "222";
var a={
    name:"111",
    say:function(){
        console.log(this.name);//这个this指向对象a
        return function(){
            console.log(this.name);//这个this指向window
        };
    }
}
var fun = a.say;
fun(); //222,相当于fun.call(window)
a.say();//111,a.say.call(a);
a.say()(); //111,222
var b={
    name:"333",
    say:function(fun){
        fun();//嵌套函数里的this指向window
    }
};
b.say(a.say);//222,因为嵌套函数里的this指向window
b.say=a.say;//b.say和a.say指向同一个函数
b.say();//333

(5)关于构造函数的new
new的过程
1、创建一个新对象;
2、将构造函数的作用域赋给新对象,即this指向新对象,同时继承该构造函数的原型;
3、执行构造函数中的代码、属性和方法添加到this指向的新对象中;
4、返回新创建的对象
(6)、ES6中箭头函数的指向
箭头函数没有自己的this,它的this是继承而来的,默认指向是在定义它时所处的对象(宿主对象)而不是执行时的对象,定义它时可能环境是window;
箭头函数可以方便地让我们在setTimeout,setInterval中方便的使用this;
箭头函数中的this是固定的,会绑定定义时所在的作用域,而不是指向运行时所在的作用域;

普通函数和箭头函数比较

普通函数

 function foo1(){
    var that = this;//将this存放在变量that中
    setTimeout(function(){
        console.log(this); //回调函数中的this指向window,输出window
        console.log(this.b);//undefined
        console.log(that);//obj1
        console.log(that.b); //2
    },1000);
}
var obj1={
    b:2
};
foo1.call(obj1);

箭头函数

function foo2(){
    var that = this;
    setTimeout(()=>{
        console.log(this); //obj2,这个this指向函数定义时所在的对象
        console.log(this.b); //2
    },1000);
}
var obj2={
    b:2
};
foo2.call(obj2);

箭头函数的注意事项:

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象;
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出错误;
  • 不可以使用arguments对象,该对象在函数体内不存在,若要用,可以用Rest参数代替;
  • 不可以使用yield命令,因此箭头函数不能用作Generator函数。

猜你喜欢

转载自blog.csdn.net/betty13006159467/article/details/80669923
今日推荐