🔥🔥🔥JavaScript难点this关键字轻松掌握——小白篇🔥🔥🔥

158 阅读5分钟

前言

    今天我们来聊一聊JS中的“this”!JavaScript 中的 this 是一个特殊关键字,它可以引用当前执行上下文中的对象。让我们先看下面一段代码:

function identify(context) {
    return context.name.toUpperCase()
}  
function speek(context) {
    var greeting = "Hello,I'm " + identify(context);
    console.log(greeting);
}    
var me = {
    name: "Tom"
}
console.log(speek(me));

    再看另一段代码:

function identify() {
    return this.name.toUpperCase()
}    
function speek() {
    var greeting = "Hello,I'm " + identify.call(this);
    console.log(greeting);
}    
var me = {
    name: "Tom"
} 
speek.call(me)

    看出区别了吗?没错!虽然他们输出的结果是一样的,都是:Hello,I'm TOM,但是后者通过使用this更方便地进行了指向,简化了我们的代码,这就是this的作用。

正文

this

    this用来代指,也就是用来简化代码——这是它的用处,那this有什么特点呢?

function foo() {
    var a = 2;
    this.bar()
}
function bar() {
    var b = 3
    console.log(this.a);
    console.log(this.b);
}
foo()

    正常我们想要的结果应该是23,但这里输出的结果都是undefined,这是为什么呢?这里的两个this都指向了全局,所以拿不到函数中的abthis不能引用一个词法作用域中的内容——这就是this的特点。

this的绑定规则

默认绑定 --- 函数在哪个词法作用域里生效,this就指向哪里。也可以简单地记为:只要是默认绑定,this就是默认指向全局。

var b = 2
function foo() {
    var b = 1
    function bar() {
        baz()
    }
    function baz() {
        console.log(this.b);
    }
    bar()
}
foo()

    猜猜答案是哪个b?正确答案是2!这就是默认绑定。绝大部分情况this指向的都是全局,但也有特殊情况,这就是我们接下来要讨论的其他绑定。

隐式绑定 --- 当函数被一个对象所拥有,再调用时,此时this会指向该对象

var a = 3
function foo() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo
}
obj.foo()

    此时this指向的结果是2,而不是全局的3,这就是隐式绑定。让我们看看错误使用:

var a = 3
function foo() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo()
}
obj.foo

    此时this指向的结果是3,而不是对象中的2,当foo不是被对象所拥有时,this就不会被对象所束缚,从而指向了全局。

隐式丢失 --- 当函数被多个对象链式调用时,this指向引用函数的对象

var a = 3
function foo() {
    console.log(this.a);
}
var obj = {
    a: 2,
    foo: foo
}
var obj2 = {
    a: 1,
    obj: obj
}
obj2.obj.foo()

    结果是指向了obj中的2,并没有被第一层的obj2所束缚,这个叫隐式丢失。

显示绑定 --- 人为干预this,让this指向谁。使用call,apply,bind

function foo() {
    console.log(this.a);
}
var obj = {
    a: 2
}
foo() 

    很明显,我们知道无法取到a。但我们要是将foo()换成foo.call(obj),这样我们就可以拿到a了。call的作用,强行把this的指向“掰”过去,此处是将this强行指向了obj,从而取到a

    让我们加个n,换个样子:

function foo(n) {
    console.log(this.a, n);
}
var obj = {
    a: 2
}
foo.call(obj, 100)

    输出结果是:2100foo在使用call方法的时候,call又反过来调用了foo,所以可能看起来有点别扭。但这样我们就把100赋给了n,那要是再多一点呢?

function foo(n, m) {
    console.log(this.a, n, m);
}
var obj = {
    a: 2
}
foo.call(obj, 100, 200)

    结果很明显,是:2100200。跟上面同理,或者使用apply

foo.call(obj, 100, 200)
//改为
foo.apply(obj, [100, 200])

    区别:apply在装参数的时候得用一个数组装起来,而不是像call一样“散装的”。再或者改成:

//1.
var bar = foo.bind(obj, 100, 200)
bar()
//2.
var bar = foo.bind(obj)
bar(100, 200)
//3.
var bar = foo.bind(obj, 100)
bar(200)

    bind会按顺序来一个个赋值。

var bar = foo.bind(obj, 100, 200)
bar(300)

    如果是像这样多出来的话300会被舍去。

new 绑定 --- 这个用的很多就不过多赘述。

箭头函数

    箭头函数没有this这个概念,写在箭头函数中的this也是它外层函数的this。

var a = 1
// 定义一个函数:
function foo() {
    console.log(this.a)
}
foo()
// 函数表达式:
var bar = function() {
    console.log(this.a);
}
bar()
// 箭头函数:
var baz = () => {
    console.log(this.a);
}
baz()

    他们拿到的都是全局里的a,区别:上面的两个函数比如bar中的this是写在bar中的函数,而箭头函数中的this是写在全局中的。这么说可能不太明白,让我们看看例子:

var obj = {
    name: "Tom",
    show: function() {
        var bar = function() { 
            console.log(this.name);
        }
        bar()
    }
}
obj.show()

    在不使用箭头函数的情况下,我们得到的结果是undefined。这时就是一层层往外指向了全局,所以拿不到obj中的Tom

var obj = {
    name: "Tom",
    show: function() {
        var bar = () => {
            console.log(this.name);
        }
        bar()
    }
}
obj.show()

    而使用箭头函数时,this就是写在了bar的外层,在这题的情况下形成了隐式绑定,从而拿到了name,输出的结果是Tom

    Tips:箭头函数不能用作构造函数:

var Foo = () => {

}
console.log(new Foo());

    像这样运行的话就会报错。

结语

    这就是今天要聊的关于this的全部了。总而言之,了解学会了如何使用this,能简化我们的代码以及给我们的代码编写带来不小的便利!如果以上内容对你有帮助的话,希望能给博主一个免费的小心心♡呀~