【JavaScript】关键字This的四种绑定规则你了解吗

448 阅读5分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第17天,点击查看活动详情

🥝前言:

本文承接上一篇文章 【JavaScript】彻彻底底的看清楚JS中this的指向问题),想学习JS中this的指向问题的可以去看一下。

🍋正文:

🍏this的四种绑定规则

🍐1、默认绑定

在一个函数体中使用this,当该函数被独立调用时,就会被默认绑定一个对象。

在默认绑定情况下,只要是独立函数调用就是指向Window。

如下展示五个案例进行深入学习,层层深入。示例代码如下:

// 案例一:
function foo1 () {
    console.log(this)
}
foo1()


// 案例二: 三个方法被调用的时候都是独立的,所以this的指向都是Window
function one () {
    console.log(this)
}
function two () {
    console.log(this)
    one()
}
function three () {
    console.log(this)
    two()
}

three()


// 案例三:
var obj = {
    name: '张三',
    foo3 () {
        console.log(this)
    }
}

var bar3 = obj.foo3
bar3() // Window


// 案例四:
function foo4 () {
    console.log(this)
}
var obj = {
    name: '张三',
    fn4: foo4
}

var bar4 = obj.fn4
bar4() // Window


// 案例五:
function foo5 () {
    function bar () {
        console.log(this)
    }
    return bar
}
var fn = foo5()
fn()

上述代码中五个案例,全部都是独立调用,所以显而易见,输出结果this都是指向Window对象

🍑2、隐式绑定

通过某个对象进行调用,也就是它的调用位置中,是通过某个对象发起的函数调用。 隐式绑定有一个前提条件

  • 必须在调用的对象内部有一个对函数的引用(比如一个属性)
  • 如果没有这样的引用,在进行调用时,会报找不到该函数的错误
  • 正式通过这个引用,间接的讲this绑定到了这个对象上

如下通过三个案例,进行隐式绑定的详细了解,示例代码如下:

// 案例一:通过隐式绑定将fn函数中的this指向obj对象
function fn () {
    console.log(this)
}
var obj = {
    name: '张三',
    studying: fn
}
obj.studying() // {name: '张三', studying: ƒ}


// 案例二:
var obj2 = {
    name: '张三',
    eating () {
        console.log(this.name + '正在吃饭')
    },
    running () {
        console.log(obj.name + '正在跑步')
    }
}
// 隐式绑定进行调用
obj2.eating()  // 张三正在吃饭
obj2.running() // 张三正在跑步

var fn = obj.eating
fn() // 独立函数调用 指向window,name为window中的name的值为空    输出结果为: 正在吃饭


// 案例三
var obj3 = {
    name: 'foo3',
    foo () {
        console.log(this)
    }
}
var obj4 = {
    name: 'foo4',
    bar: obj3.foo
}

obj4.bar() // {name: 'foo4', bar: ƒ}

上述三个案例中,三个this都被隐式绑定到了调用此方法的对象上。

🍒3、显示绑定 (call/apply/bind

显示绑定就是指使用js中的原型方法call()apply()bind(),对this进行显示绑定。 首先我们先对三个方法的概念下手,如下是参考的相关文档整理的:

①、call()

定义: call()方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

语法:

fun.call(thisArg, arg1, arg2, ...)

参数:

  • thisArg:在 fun 函数运行时指定的 this 值。if(thisArg == undefined|null) this = window,if(thisArg == number|boolean|string) this == new Number()|new Boolean()| new String()
  • arg1, arg2, ...: 指定的参数列表

返回值: 使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined

②、apply()

定义: apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。

语法:

func.apply(thisArg, [argsArray])

参数:

  • thisArg:可选的。在 func 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
  • argsArray: 可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。

返回值: 调用有指定this值和参数的函数的结果

③、bind()

定义: bind() 方法创建一个新的函数,在bind()被调用时,这个新函数的thisbind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。

语法:

function.bind(thisArg[,arg1[,arg2[, ...]]])

参数:

  • thisArg:调用绑定函数时作为this参数传递给目标函数的值。如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg。
  • arg1, arg2, ...: 当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。

返回值: 返回一个原函数的拷贝,并拥有指定的this值和初始参数。

概念介绍完了,上代码:

// call 与 apply

function foo () {
    console.log(this + 'foo函数被调用了')
}
var obj = {
    name: 'obj'
}
// 调用方法一:直接调用 指向的是全局对象(window)
foo()

// 调用方法二:  call和apply与直接调用不同的在于this的绑定不同 ,可以直接指定this的绑定对象为obj

foo.call(obj) //{name: 'obj'} 
foo.apply(obj) //{name: 'obj'}

// bind
function bar () {
    console.log(this)
}

var newBar = bar.bind('aaa')
newBar() // String {'aaa'}   解释一下 newBar()句话 很明显是直接调用应该指向全局对象window 但是bind显示绑定的优先级更高 (优先级会在下一篇文章更新)

以为这就完了吗?看了上面的代码,小伙伴们有没有一个疑问,call和apply有区别吗?

根据上面的概念我们可以很明显的看出来,两个方法接收的参数不一样,其实作用基本一致。

// call 与 apply的区别是什么?
function sum (num1, num2, num3) {
    console.log(num1 + num2 + num3)
}
sum.call('call', 10, 20, 30) // 60
sum.apply('apply', [10, 20, 30]) // 60
// call参数是单个的值,而apply的参数是一个数组,就这点差别

🍓4、new绑定

在JavaScript中,构造函数只是一些使用new操作符时被调用的函数。包括内置对象函数在内的所有函数都可以用new来调用,这种函数调用称为构造函数调用。 我们通过一个new关键字调用一个函数时(构造器),这个时候this是在调用这个构造器时创建出来的对象。 this 等于 创建出来的对象 ,这个过程就是 new 绑定。 示例代码如下:

function Person (name, sex) {
    this.name = name
    this.sex = sex
}

var p1 = new Person('张三', '男')
console.log(p1.name, p1.sex) // 张三 男
// 每次都会创建新对象赋值给this
var p2 = new Person('李红', '女')
console.log(p2.name, p2.sex) // 李红 女

名言警句:说能做的,做说过的\textcolor{red} {名言警句:说能做的,做说过的}
原创不易,还希望各位大佬支持一下\textcolor{blue}{原创不易,还希望各位大佬支持一下}
👍 点赞,你的认可是我创作的动力!\textcolor{green}{点赞,你的认可是我创作的动力!}
⭐️ 收藏,你的青睐是我努力的方向!\textcolor{green}{收藏,你的青睐是我努力的方向!}
✏️ 评论,你的意见是我进步的财富!\textcolor{green}{评论,你的意见是我进步的财富!}