A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 传鹏 黑马粉丝团   /  2019-3-10 09:00  /  1213 人查看  /  1 人回复  /   1 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 传鹏 于 2019-3-10 09:32 编辑


详解JavaScript中this的指向


很多初学JavaScript的同学,都找不准函数或者方法中的this到底指向谁,其实并没有那么复杂,只需要记住一个口诀就能正确找到this的指向:不管函数或者方法是如何声明的,要看这个函数或者方法最终是谁调用的,**谁最终调用这个函数或方法,那么这个函数或方法中的this就是谁**.下面从函数调用方式着手详细给大家介绍一下这个口诀.

1. 作为普通函数中的this

示例代码
function welcome( ) {
    console.log("黑马程序员深圳中心前端与移动开发学科欢迎大家!");
    console.log(this);
}
welcome(); //第5行
window.welcome();//第6行

大家都知道写一个全局函数相当于给window对象添加了一个方法,所以第5行调用welcome函数和第6行调用welcome函数本质是一样的,所以welcome函数最终是window对象在调用,所以welcome函数内部的this就指向了window对象.运行结果如下.


2. 作为对象的方法中的this

示例代码
var name = "黑马程序员";
var obj = {
    name: "传智播客",
    sayHi: function () {
        console.log("深圳就在这里,黑马对你不离不弃!");
        console.log(this);
    }
};
obj.sayHi();

最后1行的sayHi方法是由obj对象点出来调用的,所以sayHi方法中的this指向obj对象.所以输出的是obj对象中的name的值, 结果如下:

        

3. 综合案例

3.1 案例一

function welcome( ) {
    console.log("黑马程序员深圳中心前端与移动开发学科欢迎大家!");
    console.log(this);
}
var name = "黑马程序员";
var obj = {
    name: "传智播客",
    sayHi: function () {
        console.log("深圳就在这里,黑马对你不离不弃!"); //第10行
        console.log(this);//第11行
    }
};
welcome = obj.sayHi; //第15行
welcome(); //第16行  这个时候,这个welcome函数中的this指向谁呢?

这里要搞明白的是第15行代码的含义, 这句话的作用是把obj对象里面的sayHi函数的函数体赋值给welcome, 所以在第16行调用welcome函数的时候,执行的代码其实是obj中sayHi的函数体. 那么执行的就是第10、11行, 那么这个this是谁呢? 其实很简单,不要看这个方法是声明在obj对象里面的, 要看这个方法是在第16行调用,是window调用的,所以此时这个this是window,输出的结果就是window的name属性,就是那个全局name的值, 结果如下:


3.2 案例二

function welcome( ) {
    console.log("黑马程序员深圳中心前端与移动开发学科欢迎大家!"); //第2行
    console.log(this); //第3行
}
var name = "黑马程序员";
var obj = {
    name: "传智播客",
    sayHi: function () {
        console.log("深圳就在这里,黑马对你不离不弃!"); //第10行
        console.log(this);//第11行
    }
};
//变化在这里.....
obj.sayHi = welcome; //第15行  
obj.sayHi(); //第16行  

这个时候,obj.sayH函数中的this指向谁呢?这里同样要搞明白第15行代码的含义,这句话的意思是把welcome的函数体赋值给obj对象的sayHi函数, 所以在第16行调用obj对象的sayHi函数实际上执行的代码是第2行第3行, 那第3行的this是谁呢? 此时不要看这个welcome是怎么声明的, 要看这个代码是在第16行调用的,是obj对象点出来调用的,所以this指向obj.结果如下:

        

3.3 案例三

var name = "黑马程序员";
var p1 = {
    name: "深圳中心",
    dog: {
        name: "旺财",
        sayHi: function(){
            console.log(this);
        }
    }
}
p1.dog.sayHi();

最后一行这里给人的错觉好像sayHi方法是p1点出来调用的,事实这种想法是错误的,p1点出来的只是dog对象, sayHi方法还是由dog点出来调用的,所以sayHi方法中的this还是指向dog对象.所以输出的结果如下:


4. 构造函数中的this

4.1 直接调用构造函数

function Student(name, age){
    this.name = name; //第2行
    this.age = age;//第3行
}
var s1 = Student("黑马",12); //第6行
console.log(s1);
console.log(window.name);
console.log(window.age);

大家注意看第6行,调用Student函数的时候没有用new关键字,那么这就意味着Student函数是window点出来调用的,所以Student函数中的this就是window,那么第2行第3行就是在给window添加name和age属性,值分别是黑马和12.  然后函数内部没有写return关键字那默认返回值是undefined.所以s1接受到的是undefined. 整个输出结果如下:


4.2 使用new调用构造函数

function Student(name, age){
    this.name = name; //第2行
    this.age = age;//第3行
}
var s1 = new Student("黑马",12); //第6行
console.log(s1); //第7行

大家都知道new关键字会创建一个对象,并且会把构造函数中的this指向这个对象,并且还会把这个对象自动返回, 那么执行完第6行代码,  s1就是那个new关键字创建并返回的对象.在第2行第3行也已经给这个对象添加了name和age属性. 所以上面的代码执行结果如下:


4.3 为构造函数手动return后的情况

这里再来看看如果给构造函数添加了return关键字会如何,代码如下:

function Student(name, age) {   
this.name = name; //第2行   
this.age = age;//第3行   
console.log(this);   
return [10, 20, 30];
}
var s1 = new Student("黑马", 12); //第8行
console.log(s1); //第9行

说到这里大家就要注意,因为new关键字会自动帮我们返回他创建的对象,所以一般在构造函数中是不用写return返回值的, 那万一构造函数中就是写了return返回值会怎么样呢?  这个时候就要看return关键字后面返回的值是什么类型的,如果返回的是数值类型/字符串类型/布尔类型/null/undefined,那么会忽略这个返回值. 如果返回的值不是这些类型的,比如是一个数组或者一个对象,那么这个返回值会覆盖原来new关键字自动返回的那个对象. 所以上面代码运行的结果如下:


但是构造函数中的this还是new关键字创建的那个对象(验证看第10行输出的结果), 只是这个对象返回的时候被return关键字返回的数组给覆盖了,所以s1接受不到而已.

5.  修改函数中this的默认指向
以上我们讨论的是,默认情况下,函数中this的指向。实际上JavaScript提供了一套机制,允许我们对函数中的this指向进行修改,可以让函数中的this指向我们想要让他指向的对象。
var obj = {
    name: "张三"
};
function welcome() {
    console.log(this);
}
welcome();
大家现在都知道上述代码中welcome函数中this指向window对象, 输出的是window, 但是我们现在想让welcome函数中的this指向obj对象,那应该怎么做呢? 肯定是不能直接修改函数中this的指向的,直接修改会报错, 因为this被JavaScript设计为只读,代码如下:
var obj = {
    name: "张三"
};
function welcome() {
    this = obj; //这句代码在执行的时候,会报错,无法执行  
    console.log(this);
}
welcome();
这个时候,要实现这个效果,要想让welcome函数中的this指向obj, 就要使用函数上下文调用模式,比如call、 apply、 bind。
var obj = {
    name: "张三"
};
function welcome() {
    console.log(this);
}
welcome.call(obj); //使用函数上下文调用模式,想要让welcome中的this指向谁,就把谁传入.
这个时候,welcome函数被调用,但是welcome函数内部的this就指向obj对象了。

        关于函数上下文的调用模式,具体内容,我们将在后续章节继续为大家介绍,欢迎大家订阅关注。


更多图片 小图 大图
组图打开中,请稍候......

1 个回复

倒序浏览
lazydream 来自手机 中级黑马 2019-3-10 09:59:49
沙发
赞赞赞!
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马