函数内部:this详解(重点)

文章目录

一、引入this

        this是JavaScript的关键字之一,作为函数内部的一个特殊对象,我们通常所说的this值指的是把包含它的函数被当作方法调用时的上下文对象。

听着有点绕口,于是我简单粗暴地将上面这句话拆分成三大块,便于理解:

  1. this是函数内部的一个对象(类似于arguments)
  2. 当该函数被xxx对象调用时
  3. this的值就是xxx对象

二、this绑定规则

        当你理解了上文概括的三句话后,此时this已经向你打开了一扇门!以下我们将通过多种多样的栗子,了解this的各类令人作呕的操作

1.默认绑定

        直接不带任何修饰的赤裸裸的函数调用,this将默认绑定,一般是绑定到window象上(当函数在全局上下文中调用)

        注意:在严格模式下,调用函数时如果没有指定上下文对象,this值不会指向window,除非使用apply()call()把函数指定给一个对象,否则this值会变成undefined

举个栗子:

window.color = 'pink';
function sayColor() {
    let color = 'blue';
    console.log(this.color);
}
sayColor();

输出结果:pink

分析:根据上栏2、3,首先找到sayColor()的调用对象是谁,很明显sayColor()在全局上下文中被调用,调用对象为window对象,此时this的值就是window对象,this.color相当于window.color

2.隐性绑定

        函数调用时有了自己的上下文对象,函数的this绑定该上下文对象上

举个栗子:

window.color = 'pink';
   function sayColor() {
       let color = 'blue';
       console.log(this.color);
   }
   let obj = {
       color: 'red',
       sayColor: sayColor
   };
   obj.sayColor();

输出结果:red

分析:同理,找到sayColor()的调用对象是谁,显然是对象obj,此时this值就是对象obj,this.color相当于obj.color

补充:如果是链式的关系,如:xxx.obj.sayColor(),则采取就近原则,函数里的this默认绑定挨着最近的上下文对象

3.new绑定

        在JavaScript机制中,当我们的函数通过new关键字修饰时候,该函数作为构造函数调用,通过new关键字创建构造函数时,JavaScript为我们做了以下工作:

  1. 创建一个新对象
  2. 把该对象的_proto_指向原函数的prototype属性(继承原函数的原型)    -------后续文章介绍原型与原型链
  3. 该新对象上绑定到构造函数的this上
  4. 返回新对象,在该构造函数不返回其他对象的情况下

举个栗子:

window.name = "Matt";
function Person() {
    this.name = "Nicholas";
    this.age = 29;
    this.job = "Software Engineer";
    this.sayName = sayName;
}
function sayName() {
    console.log(this.name);    
}
// 使用new操作符作为构造函数调用,该构造函数this绑定到对象person上
let person = new Person();
person.sayName();    // Nicholas
sayName();    // Matt
console.log(person.__proto__ === Person.prototype);     // true

输出结果:Nicholas   Matt

分析:构造函数Person通过new关键字创建对象person,该对象上绑定到构造函数的this上,同理,找到sayName()的调用对象是谁,显然是对象personthis.name相当于person.name也就是构造函数的name,为Nicholas;而在全局中直接调用sayName(),该函数的this值为window对象(默认绑定),打印Matt(此段需细品)

注意:如果该构造函数内部返回其他对象的情况下,将无法返回new关键字创建的新对象,将与this失去绑定(废话,对象都没了),结果将报错

举个栗子:

function Person() {
    this.name = "Nicholas";
    this.sayName = sayName;
    return new String("哈哈哈你对象没啦!");    // 返回新对象
}
function sayName() {
    console.log(this.name);    
}
// 使用new操作符作为构造函数调用,该构造函数this绑定到对象person上
let person = new Person();
person.sayName();    // TypeError: person.sayName is not a function

4.call()、apply()、bind()显性绑定

        隐性绑定具有一个致命的限制,就是其绑定对象上下文必须包含我们的函数,如上文中let obj = { sayColor: sayColor },如果未包含我们的函数隐性绑定将会报错,也就是对象无法调用函数使得函数的this值为该对象。不可能给每个对象都声明一个属性保存该函数,那样代码的可维护性太差,因此此处引出显性绑定,给函数强制性绑定this

        apply()call()真正强大的地方是控制函数上下文(即函数体内)this值的能力

举个栗子:

window.age = 29;
let a = {
    age: 33
};
let b = {
    age: 66
};
function sayAge() {
    console.log(this.age);
}
sayAge();    // 29 this值默认为window对象
sayAge.call(a);    // 33 将this值显性切换为对象a
sayAge.apply(b);     // 66 将this值显性切换为对象b

原理call()与apply()将任意对象设置为任意函数的作用域,如:此例通过sayAge.call(a)将对象a设置为函数sayAge()的作用域,因此sayAge()函数体中打印this.age将在对象a的上下文中去寻找age并打印,即打印33;sayAge.apply(b)同理

ES5同样定义了一个新方法bind(),跟call()和apply()的不同之处在于:它控制函数this值的同时,会创建一个新的函数(准确来说是改变新函数的this值)。

举个栗子:

window.age = 29;
let a = {
    age: 33
};
function sayAge() {
    console.log(this.age);
}
let sayAgeAgain = sayAge.bind(a);    // 创建新函数sayAgeAgain
sayAgeAgain();    // 全局作用域中调用

分析:在sayAge()上调用bind()并传入对象a并且还创建了一个新函数sayAgeAgain()。此时sayAgeAgain()的this值被设置为对象a!!因此在全局作用域中调用sayAgeAgain(),也会返回33,this不会指向window。

三、箭头函数

原理箭头函数会保留定义该函数时的上下文,

举个栗子:

window.color = 'red';
let obj = {
    color: 'blue'
};
// 此时箭头函数sayColor()声明在全局上下文
let sayColor = () => console.log(this.color);
obj.sayColor = sayColor;
obj.sayColor();     // 依旧为red

输出结果:red

解析:本例中,箭头函数声明在全局上下文中,this值为window对象,我试图通过obj.sayColor = sayColor的形式隐性绑定将this值改为对象obj,再通过对象obj调用sayColor(),但输出仍然为window对象的color属性red,因为箭头函数会保留声明该函数时的上下文,我将它声明在了全局上下文中,因此其this值只能是window对象

总结

        本章节深入浅出的介绍了JavaScript函数内部的this对象的各种行为,作为热门面试知识点,基于JavaScript高级程序设计(红宝书)案例+segmentfault的各类文章阐述结合自身理解总结所作,希望对新手小白对JavaScript向更高阶语法迈进会有一定帮助,有不足之处或错误愿意接受批评指正!!语言组织不易,希望亲带着我的理解细细品读,呜呜呜!

  • 23
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JV_32

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值