前端this指向问题

this绑定分为4种情况

1. 默认绑定 (独立调用)

2. 隐式绑定 (某个对象发起的函数调用)

3. 显示绑定 (call apply bind)

4. new操作符绑定(new 构造函数)

this分析

一、 默认绑定

javascript内置API的回调函数的this指向,取决于API内部实现时对回调的调用方式

例题:

1. setTimeout

// setTimeout的回调中的this是 window

setTimeout(function () {
    console.log(this, "this1"); //浏览器中this是window,node环境是Timeout对象,
}, 1000)


setTimeout(() => {
    console.log(this, "this2");// window
}, 1000)

2. forEach

//forEach的回调如果是非箭头函数,this可以被改变

const arr = [1, 2, 3, 4, 5]
const obj = {
    name: 'nihao'
};
arr.forEach((item, idx) => {
    console.log(this, "this"); //回调是箭头函数,this是window
}) 

arr.forEach(function (item, idx) {
    console.log(this, "this2"); //回调不是箭头函数,this可以被改变,this是obj对象
}, obj) 

二、隐式绑定

const object = {
    name: 'dk',
    sayName1() {
        return this.name
    },
    sayName2: () => {
        return this.name
    }
};
console.log(object.sayName1(), "obj1") 
console.log(object.sayName2(), "obj2")

分析:

1. 通过使用 对象.函数() 的调用方式,sayName1的this被隐式绑定为了object对象
2. 箭头函数的this是定义箭头函数时的外部的作用域的this,与调用对象(object)无关。

打印:
dk obj1
undefined obj2   //sayName2函数是箭头函数,sayName2所处的外部作用域是全局作用域GO

三、显式绑定

显示绑定通过call、apply、bind改变this

例题:


var obj1 = {
    a: 1
}

var obj2 = {
    a: 2,
    bar: function () {
        console.log(this.a)
    },
    foo: function () {
        setTimeout(function () {
            console.log(this)
            console.log(this.a)

        }.call(obj1), 0)
    }
}

var a = 3
obj2.bar() 
obj2.foo() 

打印:
2
{a: 1}
1

四、new操作符绑定this 

例题:


function Foo() {
    getName = function () { console.log(1); }; //不定义直接赋值,会将getName方法放在window上。如果想放在Foo实例的属性上,需要使用this.getName定义。
    return this;
}
Foo.getName = function () { console.log(2); };
Foo.prototype.getName = function () { console.log(3); };

var getName = function () { console.log(4); }; //执行时getName赋值为这个函数

function getName() { console.log(5) }; //函数声明提升, 并优先级高于const getName这个

Foo.getName(); //第1行
getName(); //第2行
Foo().getName(); //第3行
getName(); //第4行
new Foo.getName();//第5行
new Foo().getName(); //第6行
new new Foo().getName(); //第7行

备注:

变量的getName声明和函数的声明getName会提升,函数的优先级>变量的优先级,getName会被声明为函数
执行代码时,getName被赋值为了打印4的函数,所以此时window上的getName是打印4的函数 

执行顺序:new Foo() > Foo() > new Foo

分析:
执行第一行,Foo.getName(),打印2

执行第二行,getName() ,即执行window.getName() 打印4

执行第三行,Foo().getName(),先执行Foo(),window上的getName被赋值为打印1的函数,返回window对象,再执行window.getName() 打印1

执行第4行,getName(),执行window.getName,打印1
执行第5行,new Foo.getName(),调用Foo.getName打印2,返回Foo.getName类型的对象 

执行第6行,new Foo().getName(),执行new Foo()返回Foo实例,调用实例上的getName,打印3

执行第7行,new new Foo().getName(),执行new Foo()返回Foo实例,再执行实例.getName()的,打印3

打印结果:

2

4

1

1

2

3

3

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值