JS this的问题

一、 函数的this理解

this的指向只有在代码运行时才确定的,而不是定义时确定的

  • 谁调用这个函数或方法,this关键字就指向谁,才决定了this的作用域
  • js中的this指向谁,是由调用模式决定的

二、js中的调用模式

  1. 普通函数调用
// 普通函数调用  this指向 window

function sum() {
    console.log(this); // window
}
sum();
  1. 作为方法来调用
  • 当函数被保存为一个对象的属性时,它就可称为这个对象的方法。当一个方法被调用时,this被绑定到这个对象上。
  • 如果调用表达式包含一个提取属性的动作(. 或 []),则它被称为方法调用。
// 作为方法来调用    this 指向当前对象

var peroson = {
    name: 'yian',
    age: 15,
    say(){
        console.log(this);   //{name: "yian", age: 15, say: ƒ}
        return this.name + this.age;
    }
}
peroson.say();
var o = {
    a:10,
    b:{
        a:12,
        fn:function(){
            console.log(this.a); //12
        }
    }
}
o.b.fn();
  • 这里同样也是对象o点出来的,但是同样this并没有执行它.

情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找。

情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。

情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象,例子3可以证明,如果不相信,那么接下来我们继续看几个例子。

var o = {
    a:10,
    b:{
        // a:12,
        fn:function(){
            console.log(this.a);   //undefined
        }
    }
}
o.b.fn();
  • 尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西。
  • 直接执行了fn

例:特殊的情况

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。
  1. 作为构造函数来调用

若在一个函数前加new关键字来调用,则就会创建一个连接到该函数的prototype成员的新对象,同时,this会被绑定到这个新对象上。这种情况下,这个函数就可成为此对象的构造函数。

//作为构造函数来调用     this 指向当前实例化的对象

function Animal(name, age) {
    this.name = name;
    this.age = age;
    this.run = function() {
        console.log(this);  //Animal {name: "yian", age: 5, run: ƒ}
        return this.name + ' ' + this.age;
    };
}
let animal = new Animal('yian', 5);
console.log(animal.run());   //yian 5
  1. 使用apply/call方法调用
  • 在JS中,函数也是对象,所有函数对象都有两个方法:apply和call,这两个方法可以让我们构建一个参数数组传递给调用函数,也允许我们改变this的值。
  • 在apply()、call() 方法中,接收两个参数:第一个参数是this指向;第二个参数在apply()中是数组,在call()中是普通的形参,如字符串等。

例1:使用构造函数定义一个长方形

//使用apply/call方法来调用======this指向取决于两个方法的第一个参数

function Rectangle(width, height) {
    this.width = width;
    this.height = height;
    this.getRectangle = function() {
        console.log(this);
        return `长度是:${width},高度是:${height}`;
    };
}
// 实例化一个长方形
let a = new Rectangle(10, 20);
//当调用a.getRectangle()时,Rectangle()函数中的this 指向的是它的实例
a.getRectangle();
let model = {
    width: 35,
    height: 50
};
//当model对象在调用js的call()||apply()方法后,Rectangle()函数中的this就指向了model对象
a.getRectangle.apply(model);

在这里插入图片描述
例2:使用apply(),call()方法求最大值

//Math对象有个max()方法
//由于参数是个数组,使用apply()方法 ,当第一个参数是null || undefind时,this指向window

let arr = [1, 5, 25, 68, 59];
console.log(Math.max.apply(null, arr));  //68
console.log(Math.max.apply(undefined, arr));  //68
  1. Function.prototype.bind方法

例3:异步模拟,创建一个水果模型

function Fruit(name, color) {
        this.name = name;
        this.color = color;
        this.change = function() {
            console.log(this);   //这个this指向了 Fruit {name: "苹果", color: "黑色", change: ƒ}的实例
            //1秒后打印水果的颜色
            setTimeout(function() {
                console.log(this);   //这个this指向了 Window
                console.log(this.name + '的颜色是 ' + this.color);  //苹果的颜色是 undefined
            }, 1000);
        };
    }
    let apple = new Fruit('苹果', '黑色');
    apple.change();

在这里插入图片描述

  • 在浏览器BOM中的方法,this是指向window的。因此在构造函数中Fruit()中,change()方法里的定时器里的this是指向window的,并不是当前构造函数的实例apple
  • 解决方法:用bind()将this指向绑定到当前实例化的对象;使用es6箭头函数

解决例3(法一):用bind()将this指向绑定到当前实例化的对象

function Fruit(name, color) {
    this.name = name;
    this.color = color;
    this.change = function() {
        console.log(this);   // 这个this 指向了 Fruit {name: "苹果", color: "黑色", change: ƒ}的实例
        //1秒后打印水果的颜色
        setTimeout(function() {
            console.log(this);   //此时this 指向了当前实例
            console.log(this.name + '的颜色是' + this.color);
        }.bind(this), 1000);
    };
}
let apple = new Fruit('苹果', '黑色');
apple.change();

在这里插入图片描述

  1. es6箭头函数

解决例3(法二):使用es6箭头函数

/*es6的箭头函数        es6里面this指向固定化,始终指向父级的运行上下文环境
因箭头函数没有this,因此它自身不能进行new实例化,另外箭头函数是从父级继承来的,是父级通过 call方法实现的*/
function Fruit(name, color) {
    this.name = name;
    this.color = color;
    this.change = function() {
        console.log(this);   // 这个this 指向了 Fruit {name: "苹果", color: "红色", change: ƒ}的实例
        //1秒后打印水果的名字和颜色
        setTimeout(() => {
            console.log(this); 	// 此时this也指向了当前实例
            console.log(this.name + '的颜色是' + this.color);
        }, 1000);
    };
}
let apple = new Fruit('苹果', '红色');
apple.change();
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值