iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >JavaScript之this指向实例分析
  • 659
分享到

JavaScript之this指向实例分析

2023-06-30 12:06:11 659人浏览 泡泡鱼
摘要

今天小编给大家分享一下javascript之this指向实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。默认绑定,全局

今天小编给大家分享一下javascript之this指向实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

默认绑定,全局对象

正所谓近水楼台先得月,全局对象作为对遥远的对象是作为备胎的存在,为语言边界护城河做兜底。

一般情况下,this 指向全局对象则属于默认绑定。那么什么是默认绑定呢?

this 默认绑定,通俗地可理解为函数被调用时无任何调用前缀对象的情景,由于函数调用时无调用前缀对象或函数无特定绑定,所以非严格模式下此时 this 会指向全局对象。

在非严格模式下,不同终端的全局变量对象有所区别:

• 在浏览器端,this 指向 Window 对象;

• 在 nodejs 环境,this 指向 global 对象;

• 在函数环境,this 指向 绑定当前函数的作用域;

在严格模式下:

• 在 use strict 环境, this 指向 undefined;

???? 在非严格模式下

{    console.log('window global this: ', this); // window  function fnOuter() {    console.log('fnOuter: ', this); // window  }  function windowThis() {    console.log('windowThis: ', this); // window    function fnInner() {      console.log('fnInner: ', this); // window      fnOuter();    }    fnInner();  }  windowThis();}

上述栗子中,无论函数声明在哪,在哪调用,由于函数调用时前面并未指定任何对象,这种情况下 this 均指向全局对象 window。

但须注意的是,在严格模式下,默认绑定下的 this 会指向 undefined。

???? 在严格模式下,再来看几个栗子,然后在心中记下答案

{    var mode = '在非严格模式下,this默认绑定';  function windowThis() {    console.log('windowThis: ', this);    console.log('windowThis: ', this.mode);    function fnInner() {      console.log('fnInner: ', this);      console.log('fnInner: ', this.mode);    }    fnInner();  }  function windowstrictThis() {    'use strict';    windowThis();    function fnInner() {      console.log('windowStrictThis: ', this);      console.log('windowStrictThis: ', this.mode);    }    fnInner();  }  windowStrictThis();}

建议得出答案再看下文,

一起来倒数吧,“花栗鼠。。。。。。”。

????????????️ ????????????️ ????????????️ ????????️???? ????????️???? ????????️???? ????️???????? ????️???????? ????️????????

好啦,来看正确输出吧,都答对了吧~

// windowThis:  Window{}// windowThis:  在非严格模式下,this默认绑定// fnInner:  Window{}// fnInner:  在非严格模式下,this默认绑定// windowStrictThis:  undefined// windowStrictThis:  TypeError: Cannot read property 'mode' of undefined

可见在函数内部使用严格模式声明后,this 指向变为 undefined 了,同时在函数内声明严格模式只对函数内定义的变量与函数有关,跟其调用的外部函数无关。

点石成金,隐式绑定

什么是隐式绑定呢?

this 隐式绑定:如果在函数调用的时,函数前面存在调用他的对象,那么 this 就会隐式绑定到这个调用对象上。

所以隐式绑定的关键点在于函数被调用的对象是谁,说白了就是找调用这个函数前面的点.是谁,谁就是 this 所绑定的对象了。

???? 举个栗子:

{  var mode = 'window';  var boss1 = {    mode: 'boss1',    fn() {      console.log(this.mode);    },  };  var boss2 = {    mode: 'boss2',    call: boss1.fn,    o: boss1,  };  boss2.o.fn(); // boss1  boss2.call(); // boss2  var boss1Copy = boss1.fn;  boss1Copy(); // window}

函数隐式绑定时,如果函数调用时存在多个对象,this 指向距离自己最近的对象,也就是 . 前面的对象是谁,this 就指向谁。

那么问题来了,如果删除 boss2 上的 mode,会有什么不一样呢?

???? 举个栗子:

{  var mode = 'window';  var boss1 = {    mode: 'boss1',    fn() {      console.log(this.mode);    },  };  var boss2 = {    call: boss1.fn,    o: boss1,  };  boss2.call(); // undefined}

答案是输出 undefined,因为此时由于 boss1 只是 boss2 的属性,boss1 与 boss2 的原型链各不相同相同,不属于父子关系,因此符合作用域链查找规则,所以 this 须从 boss2 上找 mode 属性,当 boss2 上不存在 mode 属性时则返回 undefined。注意不要与作用域链混淆了。

???? 下面这个例子就要小心点咯,能想出答案么?

{  var mode = 'window';  var boss1 = {    mode: 'boss1 mode',    fn() {      console.log(this.mode);    },  };  function Fn() {}  Fn.prototype.mode = 'Fn mode';  Fn.prototype.fnProto = function() {    console.log(this.mode);  };  var boss2 = {    mode: 'boss2 mode',    fn: function() {      return boss1.fn();    },    proto: new Fn(),  };  boss2.fn(); // boss1 mode  boss2.proto.fnProto(); // Fn mode}

答案是 boss1 mode 和 Fn mode 哦,猜对了吗。

涉及到原型链与作用域链的以一些区别,基本这里就不做解析了,请各自查漏补缺~。

隐式绑定丢失

相信细心的同学已经发现,上述例子有一个函数赋值给变量再调用的情景。当函数赋值再调用后,原本 this 指向会发生改变,函数的 this 不会指向其原对象,从而引起隐形绑定丢失问题。

常见引起隐形丢失的方式:

函数赋值变量再调用

???? 举个栗子:

{  var mode = 'window';  var boss1 = {    mode: 'boss1',    fn() {      console.log(this.mode);    },  };  var boss2 = {    mode: 'boss2',    call: boss1.fn,    o: boss1,  };  boss2.o.fn(); // boss1  boss2.call(); // boss2  var boss1Copy = boss1.fn;  boss1Copy(); // window}

上述案例 boss1Copy 和 boss2.call 就是函数赋值变量再调用的情况

函数以形参传递

???? 举个栗子:

{  var mode = 'window';  var boss1 = {    mode: 'boss1',    fn() {      console.log(this.mode);    },  };  function exce(params) {    params && params();  }  exce(boss1.fn); // window}

上述例子中我们将 boss1.fn 也就是一个函数传递进 exce 中执行,这里只是单纯传递了一个函数而已,this 并没有跟函数绑在一起,此时 this 指向原对象发送 丢失从而指向了 window。

可见,隐式丢失本质上是因为函数赋值引起的,在函数赋值给变量或另一个函数形参 Fn 后,在调用 Fn 时 this 会指向离其最近的对象。

指腹为婚,显式绑定

this 显式绑定:指通过 Object.prototype.call、Object.prototype.apply、Object.prototype.bind 方法改变 this 指向。

这里我将显式绑定细分为:

• 显式绑定:在运行时改变 this 指向

• call

• apply

• 显式硬绑定:一次绑定后,永久不能改变 this 指向

• bind

接下来看个例子,分别通过 call、apply、bind 改变了函数 log 的 this 指向。

???? 举个栗子:

{  function log() {    console.log(this.name);  }  var boss1 = { name: 'boss1' };  var boss2 = { name: 'boss2' };  var boss3 = { name: 'boss3' };  log.call(boss1); // boss1  log.apply(boss2); // boss2  log.bind(boss3)(); // boss3  var logBind = log.bind(boss3);  logBind.apply(boss1); // boss3  logBind.bind(boss2); // boss3}

在 JavaScript 中,当调用一个函数时,我们习惯称之为函数调用,此时函数处于一个被动的状态;而 bind、 call 与 apply 让函数从被动变主动,函数能主动选择自己的上下文,所以这种写法我们又称之为函数应用。

注意,如果在使用 bind、 call 与 apply 之类的方法改变 this 指向时,指向参数提供的是 null 或者 undefined 时, this 将指向全局对象。

???? 举个栗子:

{  var name = 'window';  function log() {    console.log(this.name);  }  var boss1 = { name: 'boss1' };  var boss2 = { name: 'boss2' };  var boss3 = { name: 'boss3' };  log.call(null); // window  log.apply(undefined); // window  log.bind(undefined)(); // window}

同样值得注意的是,bind 在显式改变 this 指向之后会返回一个新的绑定函数(bound function,BF)。绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用绑定函数通常会导致执行包装函数。

另外 简明 补充一下 call、apply、bind 的区别:

• bind:函数硬绑定 this 指向并返回一个全新函数 BF,且返回的 BF 无法再次被 call、apply、bind 改变 this 指向,且需要执行 BF 才会运行函数。

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

• call:改变 this 指向的同时还会执行函数,一个以散列形式的形参。

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

• apply:改变 this 指向的同时还会执行函数,可接受一个数组形式的形参。

• function.apply(thisArg,[param1,param2...])

call & apply 主要区别在于传参形式不同,在传参的情况下,call 的性能要高于 apply,因为 apply 在执行时还要多一步解析数组。

内有乾坤,new 绑定

严格来说,JavaScript 中的构造函数只是使用 关键字 new 调用的普通函数,它并不是一个类,最终返回的对象也不是一个实例,只是为了便于理解习惯这么说罢了。

一个比较容易忽略的会绑定 this 指向 的方法就是使用 new。当我们 new 一个函数时,就会自动把 this 绑定在新对象上,然后再调用这个函数。new 会覆盖 bind 的绑定让其无法生效。

那么 new 对函数到底起到什么作用呢,大致分为三步:

创建一个空的简单 JavaScript 对象(即{});

为步骤 1 新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象 ;

将步骤 1 新创建的对象作为 this 的上下文 ;

如果该函数没有返回对象,则返回 this。

这个过程我们称之为构造调用。

???? 那么 new 在构造调用时对 this 产生什么影响呢?请看栗子:

{  function log() {    console.log(this);  }  log(); // window{}  new log(); // log{}  var boss1 = { name: 'boss1' };  log.call(boss1); // boss1{}  new log.call(boss1); // Uncaught TypeError: log.call is not a constructor  new log.bind(boss1); // Uncaught TypeError: log.call is not a constructor  var logBind = log.bind(boss1);  logBind(); // boss1{}  new logBind(); // log{}}


当 new 一个函数时,this 会被绑定为函数本身,即使函数在 bind 改变 this 指向的情况下,关键字 new 依旧会将 this 指向为函数本身。且 new 绑定与显式绑定互不兼容。

军令如山,箭头函数

es6 的箭头函数是另类的存在,为什么要单独说呢,这是因为箭头函数中的 this 不适用上面介绍的几种绑定规则。

准确来说,箭头函数中没有 this,箭头函数的 this 指向取决于外层作用域中的 this,外层作用域或函数的 this 指向谁,箭头函数中的 this 便指向谁。

因为箭头函数里的 this 是永远指向到当前词法作用域(Lexical this)之中 ,在代码编码时就可以确定。没有其它 this 绑定方式可以覆盖。

这样的好处就是方便让回调函数的 this 使用当前的作用域,不怕引起混淆。

所以对于箭头函数,只要看它在哪里创建的就行。

???? 有点吃软饭的嫌疑,一点都不硬朗,我们来看看栗子:

{  function fn() {    return () => {      console.log('efnArrow: ', this);    };  }  function callback(cb) {    cb();  }  var boss1 = {    name: 'boss1',    fn() {      console.log('fn: ', this);    },    fnArrow: () => {      console.log('fnArrow: ', this);    },    ret() {      return function() {        console.log('ret: ', this);      };    },    retArrow() {      return () => {        console.log('retArrow: ', this);      };    },    cb() {      callback(function() {        console.log('cb: ', this);      });    },    cbArrow() {      callback(() => {        console.log('cbArrow: ', this);      });    },  };  var boss2 = {    name: 'boss2',    fn: boss1.retArrow,  };  boss1.fn(); // fn: boss1{}  boss1.fnArrow(); // fnArrow: window{}  boss1.ret()(); // ret: window{}  boss1.retArrow()(); // retArrow: boss1{}  boss1.cb(); // cb: window{}  boss1.cbArrow(); // cbArrow: boss1{}  boss1.fn.call(boss2); // fn: boss2{}  boss1.fnArrow.call(boss2); // fnArrow: window{}  boss1.ret.call(boss2)(); // ret: window{}  boss1.retArrow.call(boss2)(); // retArrow: boss2{}  boss1.ret().call(boss2); // ret: boss2{}  boss1.retArrow().call(boss2); // retArrow: boss1{}  boss1.cb.call(boss2); // cb: window{}  boss1.cbArrow.call(boss2); // cbArrow: boss2{}  var bar = boss1.retArrow.call(boss2);  bar(); // returnArrowLog: boss2{}  bar.call(boss1); // returnArrowLog: boss2{}  bar.bind(boss1)(); // returnArrowLog: boss2{}}

对 boss1.retArrow 为啥我们第一次绑定 this 并返回箭头函数后,再次改变 this 指向没生效呢?

前面说了,箭头函数的 this 取决于外层作用域的 this,boss1.retArrow 函数执行时 this 指向了 boss1,所以箭头函数的 this 也指向 boss1。除此之外,箭头函数 this 还有一个特性,那就是一旦箭头函数的 this 绑定成功,也无法被再次修改,有点硬绑定的意思。

当然,箭头函数的 this 也不是真的无法修改,我们知道箭头函数的 this 就像作用域继承一样从上层作用域找,因此我们可以修改外层函数 this 指向达到间接修改箭头函数 this 的目的,如 boss1.retArrow.call(boss2)()成功将 this 指向 boss2。

this 绑定优先级

前面已经介绍了几种 this 绑定规则,那么问题来了,如果一个函数调用存在多种绑定方法,this 最终指向谁呢?这里直接先上答案。

this 绑定优先级:

• 显式绑定 > 隐式绑定 > 默认绑定

• new 绑定 > 隐式绑定 > 默认绑定

为什么显式绑定不和 new 绑定比较呢?因为不存在这种绑定同时生效的情景,如果同时写这两种代码会直接抛错,所以大家只用记住上面的规律即可。

以上就是“JavaScript之this指向实例分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网精选频道。

--结束END--

本文标题: JavaScript之this指向实例分析

本文链接: https://www.lsjlt.com/news/328743.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • JavaScript之this指向实例分析
    今天小编给大家分享一下JavaScript之this指向实例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。默认绑定,全局...
    99+
    2023-06-30
  • JavaScript中this指向方法实例分析
    这篇文章主要讲解了“JavaScript中this指向方法实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript中this指向方法实例分...
    99+
    2024-04-02
  • JavaScript中this指向的示例分析
    小编给大家分享一下JavaScript中this指向的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!this先看代码:方法中function t...
    99+
    2023-06-25
  • JavaScript中的this关键词指向实例分析
    这篇文章主要讲解了“JavaScript中的this关键词指向实例分析”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“JavaScript中的this关键词指向实例分析”吧!1、es5中的th...
    99+
    2023-06-30
  • JavaScript中this指向问题的示例分析
    这篇文章将为大家详细讲解有关JavaScript中this指向问题的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. 箭头函数箭头函数排在第一个是因为它的 this 不会被改变,所以只要当前函数...
    99+
    2023-06-14
  • JQuery中this的指向实例分析
    这篇文章主要介绍“JQuery中this的指向实例分析”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“JQuery中this的指向实例分析”文章能帮助大家解决问题。JavaScript中的this不总...
    99+
    2023-06-30
  • JavaScript面向对象基础与this指向的示例分析
    这篇文章给大家分享的是有关JavaScript面向对象基础与this指向的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。1 、OOP的基础问题1.1什么是面向过程和面向对...
    99+
    2024-04-02
  • JavaScript基础之this指向
    目录this方法中对象中隐藏的this严格模式总结JavaScript中this也是一件很神奇 事情,在面向对象(比如java)中表示一个当前的对象引用,但是在JavaScript中...
    99+
    2024-04-02
  • Angular.JS中this指向的示例分析
    这篇文章主要介绍了Angular.JS中this指向的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。【this详解】1、谁最终调用函...
    99+
    2024-04-02
  • Javascript中this关键字指向问题的示例分析
    这篇文章主要介绍了Javascript中this关键字指向问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。测试题目第一题<...
    99+
    2024-04-02
  • es6箭头方法中this指向实例分析
    这篇文章主要介绍“es6箭头方法中this指向实例分析”,在日常操作中,相信很多人在es6箭头方法中this指向实例分析问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”es6箭头方法中this指向实例分析”的疑...
    99+
    2023-07-04
  • Javascript中函数分类&this指向的实例详解
    JS中定义函数的三种方式 通过实例来说明吧 <script> //method1 function fn() { ...
    99+
    2024-04-02
  • JavaScript中的this实例分析
    本篇内容主要讲解“JavaScript中的this实例分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JavaScript中的this实例分析”吧!普通函数中的 this我们来看例题:请给出下...
    99+
    2023-07-02
  • C++的this指针实例分析
    这篇文章主要介绍了C++的this指针实例分析的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C++的this指针实例分析文章都会有所收获,下面我们一起来看看吧。this指针是存在与类的成员函数中,指向被调用函数...
    99+
    2023-06-27
  • JavaScript 中this指向问题案例详解
    总结 全局环境 ➡️ window 普通函数 ➡️ window 或 undefined 构造函数 ...
    99+
    2024-04-02
  • javascript中 “this”的示例分析
    小编给大家分享一下javascript中 “this”的示例分析,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!一、前言:我们知道...
    99+
    2024-04-02
  • js中this的指向问题归纳的示例分析
    这篇文章给大家分享的是有关js中this的指向问题归纳的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。thisthis:上下文,会根据执行环境变化而发生指向的改变.1.单...
    99+
    2024-04-02
  • JavaScript深入刨析this的指向以及如何修改指向
    目录this方法中对象中隐藏的this严格模式可以改变this指向this 老规矩先看代码: 方法中 function test(){ console.log(this)...
    99+
    2024-04-02
  • JS箭头函数的this指向分析
    本篇内容介绍了“JS箭头函数的this指向分析”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!箭头函数是ES6中的新增特性,他没有自己的thi...
    99+
    2023-06-25
  • javascript中的this指向什么
    这篇文章主要介绍“javascript中的this指向什么”,在日常操作中,相信很多人在javascript中的this指向什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”...
    99+
    2024-04-02
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作