this的定义

函数一旦创建就有this属性
this指向本身
this指向实际调用的对象
译为“这”

this的绑定方法

①默认绑定

当一个函数没有明确的调用对象的时候,也就是单纯作为独立函数调用的时候,将对函数的this使用默认绑定:绑定到全局的window对象
例子

  1. function girl(){
  2. console.log(this);
  3. }
  4. //全局调用
  5. girl();//widows对象

例子

  1. function fire () {
  2. // 我是被定义在函数内部的函数哦!
  3. function innerFire() {
  4. console.log(this === window)
  5. }
  6. innerFire(); // 独立函数调用
  7. }
  8. fire(); // 输出true

谨记:

  • 一个函数没有明确的调用对象,默认绑定
  • 凡是函数作为独立函数调用,无论它的位置在哪里,它的行为表现,都和直接在全局环境中调用无异


②隐式绑定

当函数被一个对象“包含”的时候,我们称函数的this被隐式绑定到这个对象里面了,这时候,通过this可以直接访问所绑定的对象里面的其他属性,比如下面的name属性
例子:

  1. //第一种函数在对象内部
  2. var name = "小红"
  3. var girl = {
  4. name:"小米",
  5. detail:function()
  6. {
  7. console.log("姓名:"+this.name);
  8. }
  9. }
  10. girl.detail();//姓名:小米
  11. //第二种函数在对象外部
  12. var name = "小红"
  13. function detail()
  14. {
  15. console.log("姓名:"+this.name);
  16. }
  17. var girl = {
  18. name:"小米",
  19. detail:detail
  20. }
  21. girl.detail();//姓名:小米

谨记:


1. this是动态绑定的,或者说是在代码运行期绑定而不是在书写期
2. 函数于对象的独立性, this的传递丢失问题
**

  • 隐式绑定下,作为对象属性的函数,对于对象来说是独立的

解释:
在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的而不仅仅是效果上
定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”
(这点在隐式绑定this丢失问题中可说明)

  • 在一串对象属性链中,this绑定的是最内层的对象

例子:

  1. var obj = {
  2. a: 1,
  3. obj2: {
  4. a: 2,
  5. obj3: {
  6. a:3,
  7. getA: function () {
  8. console.log(this.a)
  9. }
  10. }
  11. }
  12. }
  13. obj.obj2.obj3.getA(); // 输出3

隐式绑定this丢失问题

例子:

  1. var obj = {
  2. a: 1, // a是定义在对象obj中的属性 1
  3. fire: function () {
  4. console.log(this.a)
  5. }
  6. }
  7. var a = 2; // a是定义在全局环境中的变量 2
  8. var fireInGrobal = obj.fire;
  9. obj.fire();
  10. //这里打印-----1
  11. fireInGrobal();
  12. //你以为是打印的是什么呢??? 1吗?
  13. //不不不,打印的是 2

上面这段简单代码的有趣之处在于:
obj.fire()与fireInGrobal()打印结果不一样, 这个于obj中的fire函数的引用( fireInGrobal)在调用的时候,行为表现(输出)完全看不出来它就是在obj内部定义的,不会指向obj对象,其原因在于:这个函数赋值的过程无法把fire所绑定的this也传递过去我们隐式绑定的this丢失了!! 从而 fireInGrobal调用的时候取得的this不是obj,而是window

③硬绑定/显式绑定

基于上面隐式绑定this丢失的问题,在这是我们想this指向不丢失,可以使用下面的方法

call/apply

  • call的基本使用方式: fn.call(object)

fn是你调用的函数,object参数是你希望函数的this所绑定的对象。

  • fn.call(object)的作用:

1.即刻调用这个函数(fn)
2.调用这个函数的时候函数的this指向object对象

  • apply与call使用很像,细微差别自行了解

例子:

  1. var obj = {
  2. a: 1, // a是定义在对象obj中的属性
  3. fire: function () {
  4. console.log(this.a)
  5. }
  6. }
  7. var a = 2; // a是定义在全局环境中的变量
  8. var fireInGrobal = obj.fire;
  9. fireInGrobal(); // 输出2
  10. fireInGrobal.call(obj); // 输出1

但是,我们其实不太喜欢这种每次调用都要依赖call的方式,我们更希望:能够一次性 返回一个this被永久绑定到obj的fireInGrobal函数,这样我们就不必每次调用fireInGrobal都要在尾巴上加上call那么麻烦了。

  1. var obj = {
  2. a: 1, // a是定义在对象obj中的属性
  3. fire: function () {
  4. console.log(this.a)
  5. }
  6. }
  7. var a = 2; // a是定义在全局环境中的变量
  8. var fn = obj.fire;
  9. var fireInGrobal = function () {
  10. fn.call(obj) //硬绑定
  11. }
  12. fireInGrobal(); // 输出1

bind

call和bind的区别是:
在绑定this到对象参数的同时:
1.call将立即执行该函数
2.bind不执行函数,只返回一个可供执行的函数

例子:**

  1. var obj = {
  2. a: 1, // a是定义在对象obj中的属性
  3. fire: function () {
  4. console.log(this.a)
  5. }
  6. }
  7. var a = 2; // a是定义在全局环境中的变量
  8. var fn = obj.fire;
  9. var fireInGrobal = fn.bind(obj);
  10. fireInGrobal(); // 输出1

在隐式绑定下:函数和只是暂时住在“包含对象“的旅馆里面,可能过几天就又到另一家旅馆住了
在显式绑定下:函数将取得在“包含对象“里的永久居住权,一直都会”住在这里“

④构造函数绑定

执行new操作的时候,将创建一个新的对象,并且将构造函数的this指向所创建的新对象
例子:

  1. function Lover(name) {
  2. this.name = name;
  3. this.sayName = function () {
  4. console.log("我的老婆是" + this.name);
  5. };
  6. }
  7. var name = "小白";
  8. var xiaoHong = new Lover("小红");
  9. xiaoHong.sayName();//我的老婆是小红

测验

例1

题目:

  1. function a() {
  2. function b() {
  3. console.log(this);
  4. function c() {
  5. "use strict";
  6. console.log(this);
  7. }
  8. c();
  9. }
  10. b();
  11. }
  12. a();

分析:

  1. function a() {
  2. function b() {
  3. console.log(this);//默认绑定
  4. function c() {
  5. "use strict";//严格模式
  6. console.log(this);//this 变为 undefined
  7. }
  8. c();
  9. }
  10. b();
  11. }
  12. a();

结果:
window
undefined

例2

题目:

  1. var name = "小白";
  2. function special() {
  3. console.log("姓名:" + this.name);
  4. }
  5. var girl = {
  6. name: "小红",
  7. detail: function () {
  8. console.log("姓名:" + this.name);
  9. },
  10. woman: {
  11. name: "小黄",
  12. detail: function () {
  13. console.log("姓名:" + this.name);
  14. },
  15. },
  16. special: special,
  17. };
  18. girl.detail();
  19. girl.woman.detail();
  20. girl.special();

分析:

  1. girl.detail();
  2. 执行girl对象下面的detail方法,即this隐式绑定,指向该方法的对象
  3. 得出:小红
  4. girl.woman.detail();
  5. 执行woman对象下面的detail方法,即this隐式绑定,指向该方法的对象
  6. 得出:小黄
  7. girl.special();
  8. 指向special属性,属性值指向special函数,已在全局声明
  9. 虽然special函数里面的this是隐式绑定
  10. 但是this指向实际调用该方法的对象,即为girl对象

结果:
姓名:小红
姓名:小黄
姓名:小红

例3

题目:

  1. var name = "小红";
  2. function a() {
  3. var name = "小白";
  4. console.log(this.name);
  5. }
  6. function d(i) {
  7. return i();
  8. }
  9. var b = {
  10. name: "小黄",
  11. detail: function () {
  12. console.log(this.name);
  13. },
  14. bibi: function () {
  15. return function () {
  16. console.log(this.name);
  17. };
  18. },
  19. };
  20. var c = b.detail;
  21. b.a = a;
  22. var e = b.bibi();
  23. a();
  24. c();
  25. b.a();
  26. d(b.detail);
  27. e();

分析:

  1. a();
  2. 全局调用a函数,a中的this默认绑定,指向全局window
  3. window.name=“小红”
  4. c();
  5. 函数c是变量名,由对象b中的detail方法赋值,detail方法是一个函数
  6. (错误想法:执行b对象下detail方法,即隐式绑定,this指向方法的对象——b)----隐式绑定this丢失
  7. 相当于普通函数赋值给c,函数产生动作console.log(this.name),赋值给c,与b无关
  8. 也就是说c函数产生动作console.log(this.name)
  9. c是在全局调用,打印小红
  10. b.a();
  11. 先看b里面没有a方法,但仔细观察b.a = a;
  12. 意思是给b定义了a属性,再a赋值,给b对象一个a方法
  13. b.a()就相当于调用b对象的a方法,this指向调用函数的对象b,打印小黄
  14. d(b.detail);
  15. b.detail作为d的参数,detail方法给了dd在全局调用
  16. 打印小红
  17. e();
  18. b里面的bibi是一个闭包(自学闭包,很重要!)
  19. e=b.bibi e=b.bibi() 不一样
  20. e=b.bibi() 相当于bibi()方法赋给了ee在全局调用
  21. 打印小红

结果:
小红
小红
小黄
小红
小红