JS之This 关键字问题

This 关键字问题

this的定义

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

this的绑定方法

①默认绑定

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

function girl(){
    console.log(this);
}
//全局调用
girl();//widows对象
例子
function fire () {
  // 我是被定义在函数内部的函数哦!
     function innerFire() {
  console.log(this === window)
      }
     innerFire(); // 独立函数调用
}
fire(); // 输出true

谨记:

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

②隐式绑定

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

//第一种函数在对象内部
var name = "小红"
var girl = {
  name:"小米",
  detail:function()
    {
      console.log("姓名:"+this.name);
    }
  }
girl.detail();//姓名:小米
//第二种函数在对象外部
var name = "小红"
function detail()
    {
      console.log("姓名:"+this.name);
    }
var girl = {
  name:"小米",
  detail:detail
  }
girl.detail();//姓名:小米

谨记:

  1. this是动态绑定的,或者说是在代码运行期绑定而不是在书写期
  2. 函数于对象的独立性, this的传递丢失问题
  • 隐式绑定下,作为对象属性的函数,对于对象来说是独立的
    解释:
    在上文中,函数虽然被定义在对象的内部中,但它和“在对象外部声明函数,然后在对象内部通过属性名称的方式取得函数的引用”,这两种方式在性质上是等价的(而不仅仅是效果上)
    定义在对象内部的函数只是“恰好可以被这个对象调用”而已,而不是“生来就是为这个对象所调用的”
    (这点在隐式绑定this丢失问题中可说明)
  • 在一串对象属性链中,this绑定的是最内层的对象
    例子:
var obj = {
      a: 1,
      obj2: {
           a: 2,
           obj3: {
                a:3,
                getA: function () {
                    console.log(this.a)   
                 }
           }
       }
}
 
obj.obj2.obj3.getA();  // 输出3

隐式绑定this丢失问题

例子:

var obj = {
      a: 1,    // a是定义在对象obj中的属性   1
      fire: function () {
   console.log(this.a)
        }
      }
 
var a = 2;  // a是定义在全局环境中的变量    2
var fireInGrobal = obj.fire;  
obj.fire();
//这里打印-----1
fireInGrobal(); 
//你以为是打印的是什么呢???   1吗?
//不不不,打印的是 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使用很像,细微差别自行了解
    例子:
var obj = {
      a: 1,    // a是定义在对象obj中的属性
      fire: function () {
         console.log(this.a)
      }
}
 
var a = 2;  // a是定义在全局环境中的变量  
var fireInGrobal = obj.fire;
fireInGrobal();   // 输出2
fireInGrobal.call(obj); // 输出1

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

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

bind

call和bind的区别是:
在绑定this到对象参数的同时:

  1. call将立即执行该函数
  2. bind不执行函数,只返回一个可供执行的函数
    例子:
var obj = {
      a: 1,    // a是定义在对象obj中的属性
      fire: function () {
        console.log(this.a)
      }
}
 
var a = 2;  // a是定义在全局环境中的变量  
var fn = obj.fire;
var fireInGrobal = fn.bind(obj);
       
fireInGrobal(); // 输出1

隐式与显式的区别

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

④构造函数绑定

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

function Lover(name) {
  this.name = name;
  this.sayName = function () {
    console.log("我的老婆是" + this.name);
  };
}
var name = "小白";
var xiaoHong = new Lover("小红");
xiaoHong.sayName();//我的老婆是小红

测验

例1

题目:

function a() {
  function b() {
    console.log(this);
    function c() {
      "use strict";
      console.log(this);
    }
    c();
  }
  b();
}
a();

分析:

function a() {
  function b() {
    console.log(this);//默认绑定
    function c() {
      "use strict";//严格模式
      console.log(this);//this 变为 undefined
    }
    c();
  }
  b();
}
a();

结果:

window
undefined

例2

题目:

var name = "小白";
function special() {
  console.log("姓名:" + this.name);
}
var girl = {
  name: "小红",
  detail: function () {
    console.log("姓名:" + this.name);
  },
  woman: {
    name: "小黄",
    detail: function () {
      console.log("姓名:" + this.name);
    },
  },
  special: special,
};
girl.detail();
girl.woman.detail();
girl.special();

分析:

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

结果:

姓名:小红
姓名:小黄
姓名:小红

例3

题目:

var name = "小红";
function a() {
  var name = "小白";
  console.log(this.name);
}
function d(i) {
  return i();
}
var b = {
  name: "小黄",
  detail: function () {
    console.log(this.name);
  },
  bibi: function () {
    return function () {
      console.log(this.name);
    };
  },
};
var c = b.detail;
b.a = a;
var e = b.bibi();
a();
c();
b.a();
d(b.detail);
e();

分析:

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

结果:

小红
小红
小黄
小红
小红
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值