JS:this的绑定规则

一、默认绑定

this默认指向了window全局对象。

1.全局环境下的this指向了window
console.log(this); // Window
2.函数独立调用,函数内部的this也指向了window
function fn(){
    console.log(this);
}
fn(); // Window
3.被嵌套的函数独立调用时,this默认指向了window
var a = 0;
var obj = {
    a: 2,
    foo: function() {
        // 函数当做对象的方法来调用,this指向了obj
        console.log(this.a); // 2
        // 当调用obj.foo时,相当于test()独立调用
        function test() {
            console.log(this); // Window
            console.log(this.a); // 0
        }
        test();
    }
}
obj.foo();
4.IIFE(声明函数的同时立即调用这个函数)自执行函数中内部的this指向了window
var a = 10;
function foo(){
    console.log(this.a); // 2
    (function test(){
        console.log(this) // Window
        console.log(this.a); // 10
    })();
}
var obj = {
    a: 2,
    foo: foo,
}
obj.foo();

(function() {
    console.log('自执行函数中内部的this:', this); // Window
})()
5.闭包中this默认指向了window
var a = 0;
var obj = {
    a: 2,
    foo: function(){
        var _this = this;
        return function test(){
            console.log(this) // Window
            console.log(this.a) // 0
            console.log(_this.a) // 2
            return _this.a;
        }
    }
}
var fn = obj.foo();
console.log(fn()); // 2

二、隐式绑定

当函数当做方法来调用,this指向了直接对象(.前面的对象)。

function foo(){
    console.log(this.a);
}
var obj = {
    a: 1,
    foo: foo,
    obj2: {
        a: 2,
        foo: foo
    }
}
// foo()函数的直接对象时obj,this的指向指向了直接对象
obj.foo(); // 1
// foo()函数的直接对象时obj2,this的指向指向了直接对象
obj.obj2.foo(); // 2

三、隐式丢失

隐式丢失就是指被隐式绑定的函数丢失了绑定对象,从而默认绑定到window。

这种情况比较容易出错却又非常常见。

1.函数别名
var a = 0;
function foo(){
    console.log(this.a)
}
var obj = {
    a: 1,
    foo: foo,
}
// 把obj.foo赋值给别名bar,造成隐式丢失的情况。因为只是把obj.foo赋值了bar变量,而bar与obj对象毫无关系
var bar = obj.foo;
bar(); // 0

// 相当于
// var a = 0;
// var bar = function foo(){
//   console.log(this.a);
// }
// bar(); // 0
2.参数传递
var a = 0;
function foo(){
    console.log(this.a)
}
function bar(fn){
    fn();
}
var obj = {
    a: 1,
    foo: foo
}
// 把obj.foo当做参数传递到bar函数中,有隐式的函数赋值,fn = obj.foo,只是把foo函数赋值给了fn,而fn与obj对象毫无关系,所以当前foo函数内部的this指向了window
bar(obj.foo) // 0

// 相当于
// var a = 0;
// function bar(fn){
//   fn();
// }
// bar(function foo(){
//   // 内部的this指向了window
//   console.log(this.a); // 0
// })
3.内置函数setTimeout()和setInterval()第一个参数的回调函数中的this默认指向了window,跟第二种情况是类似
var a = 10;
function foo(){
    console.log(this.a);
}
var obj = {
    a: 1,
    foo: foo
};
setTimeout(obj.foo, 1000); // 10
4.间接调用
function foo(){
    console.log(this.a);
}
var a = 2;
var obj = {
    a: 3,
    foo: foo
}
var p = {a: 4};
// 隐式绑定,函数当做对象中的方法来使用,内部的this指向了该对象
obj.foo(); // 3
// 将obj.foo函数对象赋值给p.foo函数,然后立即执行,相当于仅仅是foo()函数的立即调用,内部的this默认指向了window
(p.foo = obj.foo)(); // 2

// 将obj.foo赋值给p.foo函数,之后p.foo()函数再执行,其实是属于p对象的方法的指向,this指向了当前的p对象
p.foo = obj.foo;
p.foo(); // 4
5.其他情况,指向了window的特殊情况
var a = 0;
var obj = {
    a: 1,
    foo: foo
}
function foo(){
    console.log(this.a);
}
// 立即执行指向window
(obj.foo = obj.foo)(); // 0
(false || obj.foo)(); // 0
(1, obj.foo)(); // 0

四、显式绑定
1.call()、apply()、bind()把对象绑定到this上,叫做显示绑定
var a = 0;
function foo(){
    console.log(this.a);
}
var obj = {
    a: 2
}
foo(); // 0
// foo.call(obj); // 2
// foo.apply(obj); // 2
var fn = foo.bind(obj)
fn(); // 2

硬绑定是显式绑定的一个变种,使得this不能再被改变

var a = 0;
function foo(){
    console.log(this.a);
}
var obj = {
    a: 2
}
var bar = function(){
    foo.call(obj); // 无论bar怎么调用,最终都会绑定到obj上
}
bar(); // 2
setTimeout(bar, 2000); // 2
bar.call(window); // 2
2.数组的forEach(fn, 对象) (还有map()/filter()/some()/every()也类似)

forEach可以传入两个参数,第一个是执行函数,第二个是作用域对象(this指向对象)

var id = 'window';
function fn(el){
    console.log(el, this.id)
}
var obj = {
    id: 'fn'
}
var arr = [1, 2, 3];
// arr.forEach(fn); // window
arr.forEach(fn, obj); // fn

// 相当于
// arr.forEach(function(el, index){
//   console.log(el, index, this.id); // 1 0 'fn'
// }, obj);

五、new绑定

如果是new关键字来执行函数,相当于构造函数来实例化对象,那么内部的this指向了当前实例化的对象

function fn1(){
    console.log(this);
    return;
}
var fn = new fn1(); // fn1{}
console.log(fn); // fn1{}

当使用return关键字来返回对象的时候,实例化出来的对象是当前的返回对象

function fn2(){
    // this还是指向了当前的对象
    console.log(this);
    return {
        name: 'mjj'
    }
}
var fn = new fn2(); // fn2{}
console.log(fn); // {name: 'mjj'}

改变一下例子

function fn2(){
    // this还是指向了当前的对象
    this.a = 20
    console.log(this.a);
    // 使用return关键字来返回对象的时候,实例化出来的对象是当前的返回对象
    return {
        a: 30,
        name: 'mjj'
    }
}
var fn = new fn2(); // 20
console.log(fn.a); // 30

六、严格模式下this的指向
1.严格模式下,独立调用的函数内部的this指向了undefined
function fn(){
    // console.log(this); // Window

    'use strict';
    console.log(this); // undefined
}
fn();
2.严格模式下,函数apply()和call()内部的this始终是它们的第一个参数
function show(){
    // console.log(this) // Window

    'use strict';
    console.log(this); // null
}
show.call(null);

七、总结
1.this的四种绑定分别对应函数的四种调用
this绑定函数调用
默认绑定独立调用
隐式绑定方法调用
显式绑定间接调用 call() apply() bind()
new绑定构造函数调用
2.this隐式丢失

(1)函数别名

(2)函数当做参数传递

(3)内置函数

(4)间接调用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值