javascript】函数中的this的四种绑定形式 — 大家准备好瓜子,我要讲故事啦~~

📅 2026/7/2 4:29:44
javascript】函数中的this的四种绑定形式 — 大家准备好瓜子,我要讲故事啦~~
【故事】有一个年轻人叫迪斯this,有一天迪斯不小心穿越到一个叫“伽瓦斯克利”javascript的 异世界此时此刻迪斯身无分文 他首先要做的事情就是——找到他的住宿的地方——调用函数的对象回到顶部this的默认绑定【故事——线路1】如果迪斯this直到天黑前都没有找到能收留自己的住所他眼看就要过上非洲难民的生活 这时候一位乐善好施的魔法师村长——window救世主一般地出现了先住在我家吧【正文】当一个函数没有明确的调用对象的时候也就是单纯作为独立函数调用的时候将对函数的this使用默认绑定绑定到全局的window对象function fire () { console.log(this window) } fire(); // 输出true上面的例子我相信对大多数人都很简单但有的时候我们把例子变一下就会具有迷惑性function fire () { // 我是被定义在函数内部的函数哦 function innerFire() { console.log(this window) } innerFire(); // 独立函数调用 } fire(); // 输出true函数 innerFire在一个外部函数fire里面声明且调用那么它的this是指向谁呢 仍然是window许多人可能会顾虑于fire函数的作用域对innerFire的影响但我们只要抓住我们的理论武器——没有明确的调用对象的时候将对函数的this使用默认绑定绑定到全局的window对象便可得正确的答案了下面这个加强版的例子也是同样的输出truevar obj { fire: function () { function innerFire() { console.log(this window) } innerFire(); // 独立函数调用 } } obj.fire(); //输出 true【注意】在这个例子中 obj.fire()的调用实际上使用到了this的隐式绑定这就是下面我要讲的内容这个例子我接下来还会继续讲解【总结】 凡事函数作为独立函数调用无论它的位置在哪里它的行为表现都和直接在全局环境中调用无异回到顶部this的隐式绑定【故事——线路2】 迪斯this穿越来异世界“伽瓦斯克利”javascript的时候刚好身上带了一些钱于是他找到一个旅馆住宿了下来当函数被一个对象“包含”的时候我们称函数的this被隐式绑定到这个对象里面了这时候通过this可以直接访问所绑定的对象里面的其他属性比如下面的a属性var obj { a: 1, fire: function () { console.log(this.a) } } obj.fire(); // 输出1现在我们需要对平常司空见惯的的代码操作做一些更深的思考首先下面的这两段代码达到的效果是相同的// 我是第一段代码 function fire () { console.log(this.a) } var obj { a: 1, fire: fire } obj.fire(); // 输出1 // 我是第二段代码 var obj { a: 1, fire: function () { console.log(this.a) } } obj.fire(); // 输出1fire函数并不会因为它被定义在obj对象的内部和外部而有任何区别也就是说在上述隐式绑定的两种形式下fire通过this还是可以访问到obj内的a属性这告诉我们1. this是动态绑定的或者说是在代码运行期绑定而不是在书写期2. 函数于对象的独立性 this的传递丢失问题下面的描述可能带有个人的情感倾向而显得不太严谨但这是因为我希望阅读者尽可能地理解我想表达的意思隐式绑定下作为对象属性的函数对于对象来说是独立的基于this动态绑定的特点写在对象内部作为对象属性的函数对于这个对象来说是独立的。函数并不被这个外部对象所“完全拥有”我想表达的意思是在上文中函数虽然被定义在对象的内部中但它和“在对象外部声明函数然后在对象内部通过属性名称的方式取得函数的引用”这两种方式在性质上是等价的而不仅仅是效果上定义在对象内部的函数只是“恰好可以被这个对象调用”而已而不是“生来就是为这个对象所调用的”借用下面的隐式绑定中的this传递丢失问题来说明var obj { a: 1, // a是定义在对象obj中的属性 1 fire: function () { console.log(this.a) } } var a 2; // a是定义在全局环境中的变量 2 var fireInGrobal obj.fire; fireInGrobal(); // 输出 2上面这段简单代码的有趣之处在于 这个于obj中的fire函数的引用 fireInGrobal在调用的时候行为表现输出完全看不出来它就是在obj内部定义的其原因在于我们隐式绑定的this丢失了 从而 fireInGrobal调用的时候取得的this不是obj而是window上面的例子稍微变个形式就会变成一个可能困扰我们的bug:var a 2; var obj { a: 1, // a是定义在对象obj中的属性 fire: function () { console.log(this.a) } } function otherFire (fn) { fn(); } otherFire(obj.fire); // 输出2在上面我们的关键角色是otherFire函数它接受一个函数引用作为参数然后在内部直接调用但它做的假设是参数fn仍然能够通过this去取得obj内部的a属性但实际上, this对obj的绑定早已经丢失了所以输出的是全局的a的值(2),而不是obj内部的a的值1在一串对象属性链中this绑定的是最内层的对象在隐式绑定中如果函数调用位置是在一串对象属性链中this绑定的是最内层的对象。如下所示var obj { a: 1, obj2: { a: 2, obj3: { a:3, getA: function () { console.log(this.a) } } } } obj.obj2.obj3.getA(); // 输出3回到顶部this的显式绑定(call和bind方法)【故事——线路3】 迪斯this穿越来异世界“伽瓦斯克利”javascript经过努力的打拼积累了一定的财富于是他买下了自己的房子上面我们提到了this的隐式绑定所存在的this绑定丢失的问题也就是对于 “ fireInGrobal obj.fire”fireInGrobal调用和obj.fire调用的结果是不同的因为这个函数赋值的过程无法把fire所绑定的this也传递过去。这个时候call函数就派上用场了call的基本使用方式 fn.call(object)fn是你调用的函数object参数是你希望函数的this所绑定的对象。fn.call(object)的作用1.即刻调用这个函数fn2.调用这个函数的时候函数的this指向object对象例子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