搜尋
首頁web前端js教程詳解this指向,讓你一篇搞懂this、call、apply

詳解this指向,讓你一篇搞懂this、call、apply

目錄

  • #前言思考題
  • 一、this的指向
  • 二、call和apply
  • 三、模擬實作一個call
  • 四、bind

詳解this指向,讓你一篇搞懂this、call、apply

  • 前言思考題
記得當時找實習的時候,總是會在履歷上加上一句-熟悉Js,例如this指向、call、apply等…

詳解this指向,讓你一篇搞懂this、call、apply

#(免費學習推薦:

javascript影片教學

  • 而每次投遞履歷時我都會經歷以下步驟

面試前,去問度娘-this指向可以分為哪幾種啊~、call和apply的差別是什麼?底氣由0% 猛漲到了50%;面試中,面試官隨便扔上來幾道題,我都可以「堅定的」給出答案,結果總是不盡人意…

    面試後,我會羞愧的刪除掉履歷上的這條。而再之後投遞履歷時我又再加上了這一條…

#思考題下面幾題是我在網路上搜尋出來的熱度較高的問題,如果大佬們可以輕鬆的回答上,並有清晰的思路,不妨直接點個贊吧(畢竟也消耗了不少腦細胞),如果大佬們能在評論處指點一二,就更好了! ! !

填空題:

執行Javascript中的

【 】

函數會建立一個新函數,新函數與被調函數具有相同的函數體,當目標函數被呼叫時this 值指向第一個參數。

詳解this指向,讓你一篇搞懂this、call、apply

問答題:

  • 請你談談改變函數內部this指標的指向函數有哪幾種,他們的差異是什麼?
  • this的指向可以分為哪幾種?
    • 程式碼分析題:
    var name = 'window'var person1 = {
      name: 'person1',
      show1: function () {
        console.log(this.name)
      },
      show2: () => console.log(this.name),
      show3: function () {
        return function () {
          console.log(this.name)
        }
      },
      show4: function () {
        return () => console.log(this.name)
      }}var person2 = { name: 'person2' }person1.show1()person1.show1.call(person2)person1.show2()person1.show2.call(person2)person1.show3()()person1.show3().call(person2)person1.show3.call(person2)()person1.show4()()person1.show4().call(person2)person1.show4.call(person2)()
  • 一、this的指向
  • 百度、Google上輸入「this的指向」關鍵字,大幾千條文章肯定是有的,總不至於為了全方面、無死角的掌握它就要將所有的文章都看一遍吧?所以不如梳理出一個穩固的框架,順著我們的思路來填充它。
心智圖
  • 本節精華:this 總是(非嚴格模式下)指向一個對象,而具體指向哪個物件是在執行時期基於函數的
  • 執行環境
  • 動態綁定的,而非函數被宣告時的環境;
  • 除了不常用的with和eval的情況,具體到實際應用中,this指向大概可以分為四種:

    作為物件的方法呼叫;

    #作為普通函數呼叫;

    建構器呼叫;

    call 或apply呼叫;

    箭頭函數中,this指向函數上層作用域的this;

    ##建構子

    普通函數

    的差別在於

    被呼叫的方式

    A,call(B) => 可以理解成在B的作用域內呼叫了A方法;

    分析

    1、作為物件的方法呼叫

    當函數作為物件的方法被呼叫時,this指向該物件

    var obj = {
        a: 'yuguang',
        getName: function(){
            console.log(this === obj);
            console.log(this.a);
        }};obj.getName(); // true yuguang
    2、作為普通函數調用

    當函數不作為物件的屬性被調用,而是以普通函數的方式,this總是指向全域物件(在瀏覽器中,通常是Window物件)

    window.name = 'yuguang';var getName = function(){
        console.log(this.name);};getName(); // yuguang

    或是下面這段迷惑性的程式碼:

    window.name = '老王'var obj = {
        name: 'yuguang',
        getName: function(){
            console.log(this.name);
        }};var getNew = obj.getName;getNew(); // 老王

    而在ES5的嚴格模式下,this被規定為不會指向全域對象,而是undefined

    3、建構器呼叫

    除了一些內建函數,大部分Js中的函數都可以成為建構器,它們與普通函數沒什麼不同

    建構器###和###普通函數###的差別在於###被呼叫的方式###:###當new運算子呼叫函數時,總是會傳回一個對象,this通常也指向這個物件###
    var MyClass = function(){
        this.name = 'yuguang';}var obj = new MyClass();obj.name; // yuguang
    ###但是,如果顯式的回傳了一個object對象,那麼此運算結果最終會傳回這個物件。 ###
    var MyClass = function () {
        this.name = 1;
        return {
            name: 2
        }}var myClass = new MyClass(); console.log('myClass:', myClass); // { name: 2}
    ###只要建構器不顯示的回傳任何數據,或傳回非物件類型的數據,就不會造成上述問題。 #########4、call或apply呼叫#########跟普通的函數呼叫相比,用call和apply可以動態的改變函數的this###
    var obj1 = {
        name: 1,
        getName: function (num = '') {
            return this.name + num;
        }};var obj2 = {
        name: 2,};// 可以理解成在 obj2的作用域下调用了 obj1.getName()函数console.log(obj1.getName()); // 1console.log(obj1.getName.call(obj2, 2)); // 2 + 2 = 4console.log(obj1.getName.apply(obj2, [2])); // 2 + 2 = 4
    ### ###5.箭頭函數#########箭頭函數不會建立自己的this,它只會從自己的作用域鏈的上一層繼承this。 ###

    因此,在下面的代码中,传递给setInterval的函数内的this与封闭函数中的this值相同:

    this.val = 2;var obj = {
        val: 1,
        getVal: () => {
            console.log(this.val);
        }}obj.getVal(); // 2

    常见的坑

    就像标题一样,有的时候this会指向undefined

    情况一

    var obj = {
        name: '1',
        getName: function (params) {
            console.log(this.name)
        }};obj.getName();var getName2 = obj.getName;getName2();

    这个时候,getName2()作为普通函数被调用时,this指向全局对象——window。

    情况二

    当我们希望自己封装Dom方法,来精简代码时:

    var getDomById = function (id) {
        return document.getElementById(id);};getDomById('p1') //dom节点

    那么我们看看这么写行不行?

    var getDomById = document.getElementByIdgetDomById('p1') // Uncaught TypeError: Illegal invocation(非法调用)

    这是因为:

    • 当我们去调用document对象的方法时,方法内的this指向document
    • 当我们用getId应用document内的方法,再以普通函数的方式调用,函数内容的this就指向了全局对象。

    利用call和apply修正情况二

    document.getElementById = (function (func) {
        return function(){
            return func.call(document, ...arguments)
        }})(document.getElementById) // 利用立即执行函数将document保存在作用域中

    詳解this指向,讓你一篇搞懂this、call、apply

    二、call和apply

    不要因为它的“强大”而对它产生抗拒,了解并熟悉它是我们必须要做的,共勉!

    思维导图

    詳解this指向,讓你一篇搞懂this、call、apply

    1.call和apply区别

    先来看区别,是因为它们几乎没有区别,下文代码实例call和apply都可以轻易的切换。

    当它们被设计出来时要做到的事情一摸一样,唯一的区别就在于传参的格式不一样

    • apply接受两个参数
      • 第一个参数指定了函数体内this对象的指向
      • 第二个参数为一个带下标的参数集合(可以是数组或者类数组)
    • call接受的参数不固定
      • 第一个参数指定了函数体内this对象的指向
      • 第二个参数及以后为函数调用的参数

    因为在所有(非箭头)函数中都可以通过arguments对象在函数中引用函数的参数。此对象包含传递给函数的每个参数,它本身就是一个类数组,我们apply在实际使用中更常见一些。

    call是包装在apply上面的语法糖,如果我们明确的知道参数数量,并且希望展示它们,可以使用call。

    当使用call或者apply的时候,如果我们传入的第一个参数为null,函数体内的this会默认指向宿主对象,在浏览器中则是window

    借用其他对象的方法

    我们可以直接传null来代替任意对象

    Math.max.apply(null, [1, 2, 3, 4, 5])

    2.call和apply能做什么?

    使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数——来时MDN

    • 调用构造函数来实现继承;
    • 调用函数并且指定上下文的 this;
    • 调用函数并且不指定第一个参数;

    1.调用构造函数来实现继承

    通过“借用”的方式来达到继承的效果:

    function Product(name, price) {
    	this.name = name;
    	this.price = price;}function Food(name, price) {
    	Product.call(this, name, price); //
    	this.category = food;}var hotDog = new Food('hotDog', 20);

    2.调用函数并且指定上下文的 this

    此时this被指向了obj

    function showName() {
        console.log(this.id + ':' + this.name);};var obj = {
        id: 1,
        name: 'yuguang'};showName.call(obj)

    3.使用call单纯的调用某个函数

    Math.max.apply(null, [1,2,3,10,4,5]); // 10

    詳解this指向,讓你一篇搞懂this、call、apply

    三、模拟实现一个call

    先来看一下call帮我们需要做什么?

    var foo = {
    	value: 1};function show() {
    	console.log(this.value);};show.call(foo); //1

    就像解方程,要在已知条件中寻找突破哦口:

    • call 使得this的指向变了,指向了foo;
    • show 函数被执行了;
    • 传入的参数应为 this + 参数列表;

    第一版代码

    上面提到的3点,仅仅完成了一点,且传入的参数

    var foo = {
        value: 1};function show() {
        console.log(this.value);};Function.prototype.setCall = function (obj) {
        console.log(this); // 此时this指向show
        obj.func = this; // 将函数变成对象的内部属性
        obj.func(obj.value); // 指定函数
        delete obj.func // 删除函数,当做什么都没发生~}show.setCall(foo);

    第二版代码

    为了解决参数的问题,我们要能获取到参数,并且正确的传入:

    var foo = {
        value: 1};function show(a, b) {
        console.log(this.value);
        console.log(a + b);};Function.prototype.setCall = function (obj) {
        obj.fn = this; // 将函数变成对象的内部属性
        var args = [];
        for(let i = 1; i <p>此时,我们就可以做到,传入多个参数的情况下使用call了,但是如果你仅想用某个方法呢?</p><p><strong>第三版代码</strong></p><pre class="brush:php;toolbar:false">Function.prototype.setCall = function (obj) {
        var obj = obj || window;
        obj.fn = this;
        var args = [];
        for(var i = 1, len = arguments.length; i <p><strong>四、bind</strong></p><blockquote><p>bind() 方法创建一个新的函数,在 bind() 被调用时,这个新函数的 this 被指定为 bind() 的第一个参数,而其余参数将作为新函数的参数,供调用时使用 —— MDN</p></blockquote><p>提到了<strong>call</strong>和<strong>apply</strong>,就绕不开<strong>bind</strong>。我们试着来模拟一个bind方法,以便加深我们的认识:</p><pre class="brush:php;toolbar:false">Function.prototype.bind = function (obj) {
        var _this = this; // 保存调用bind的函数
        var obj = obj || window; // 确定被指向的this,如果obj为空,执行作用域的this就需要顶上喽
        return function(){
            return _this.apply(obj, arguments); // 修正this的指向
        }};var obj = {
        name: 1,
        getName: function(){
            console.log(this.name)
        }};var func = function(){
        console.log(this.name);}.bind(obj);func(); // 1

    这样看上去,返回一个原函数的拷贝,并拥有指定的 this 值,还是挺靠谱的哦~

    写在最后

    JavaScript內功基礎部分第一篇,總結這個系列是受到了冴羽大大的鼓勵和啟發,本系列大約會有15篇文章,都是我們在面試最高頻的,但在工作中常常被忽略的。

    相關免費學習推薦:javascript#(影片)

    #########

    以上是詳解this指向,讓你一篇搞懂this、call、apply的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文轉載於:CSDN。如有侵權,請聯絡admin@php.cn刪除
    Python vs. JavaScript:開發環境和工具Python vs. JavaScript:開發環境和工具Apr 26, 2025 am 12:09 AM

    Python和JavaScript在開發環境上的選擇都很重要。 1)Python的開發環境包括PyCharm、JupyterNotebook和Anaconda,適合數據科學和快速原型開發。 2)JavaScript的開發環境包括Node.js、VSCode和Webpack,適用於前端和後端開發。根據項目需求選擇合適的工具可以提高開發效率和項目成功率。

    JavaScript是用C編寫的嗎?檢查證據JavaScript是用C編寫的嗎?檢查證據Apr 25, 2025 am 12:15 AM

    是的,JavaScript的引擎核心是用C語言編寫的。 1)C語言提供了高效性能和底層控制,適合JavaScript引擎的開發。 2)以V8引擎為例,其核心用C 編寫,結合了C的效率和麵向對象特性。 3)JavaScript引擎的工作原理包括解析、編譯和執行,C語言在這些過程中發揮關鍵作用。

    JavaScript的角色:使網絡交互和動態JavaScript的角色:使網絡交互和動態Apr 24, 2025 am 12:12 AM

    JavaScript是現代網站的核心,因為它增強了網頁的交互性和動態性。 1)它允許在不刷新頁面的情況下改變內容,2)通過DOMAPI操作網頁,3)支持複雜的交互效果如動畫和拖放,4)優化性能和最佳實踐提高用戶體驗。

    C和JavaScript:連接解釋C和JavaScript:連接解釋Apr 23, 2025 am 12:07 AM

    C 和JavaScript通過WebAssembly實現互操作性。 1)C 代碼編譯成WebAssembly模塊,引入到JavaScript環境中,增強計算能力。 2)在遊戲開發中,C 處理物理引擎和圖形渲染,JavaScript負責遊戲邏輯和用戶界面。

    從網站到應用程序:JavaScript的不同應用從網站到應用程序:JavaScript的不同應用Apr 22, 2025 am 12:02 AM

    JavaScript在網站、移動應用、桌面應用和服務器端編程中均有廣泛應用。 1)在網站開發中,JavaScript與HTML、CSS一起操作DOM,實現動態效果,並支持如jQuery、React等框架。 2)通過ReactNative和Ionic,JavaScript用於開發跨平台移動應用。 3)Electron框架使JavaScript能構建桌面應用。 4)Node.js讓JavaScript在服務器端運行,支持高並發請求。

    Python vs. JavaScript:比較用例和應用程序Python vs. JavaScript:比較用例和應用程序Apr 21, 2025 am 12:01 AM

    Python更適合數據科學和自動化,JavaScript更適合前端和全棧開發。 1.Python在數據科學和機器學習中表現出色,使用NumPy、Pandas等庫進行數據處理和建模。 2.Python在自動化和腳本編寫方面簡潔高效。 3.JavaScript在前端開發中不可或缺,用於構建動態網頁和單頁面應用。 4.JavaScript通過Node.js在後端開發中發揮作用,支持全棧開發。

    C/C在JavaScript口譯員和編譯器中的作用C/C在JavaScript口譯員和編譯器中的作用Apr 20, 2025 am 12:01 AM

    C和C 在JavaScript引擎中扮演了至关重要的角色,主要用于实现解释器和JIT编译器。1)C 用于解析JavaScript源码并生成抽象语法树。2)C 负责生成和执行字节码。3)C 实现JIT编译器,在运行时优化和编译热点代码,显著提高JavaScript的执行效率。

    JavaScript在行動中:現實世界中的示例和項目JavaScript在行動中:現實世界中的示例和項目Apr 19, 2025 am 12:13 AM

    JavaScript在現實世界中的應用包括前端和後端開發。 1)通過構建TODO列表應用展示前端應用,涉及DOM操作和事件處理。 2)通過Node.js和Express構建RESTfulAPI展示後端應用。

    See all articles

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱工具

    SublimeText3 英文版

    SublimeText3 英文版

    推薦:為Win版本,支援程式碼提示!

    VSCode Windows 64位元 下載

    VSCode Windows 64位元 下載

    微軟推出的免費、功能強大的一款IDE編輯器

    PhpStorm Mac 版本

    PhpStorm Mac 版本

    最新(2018.2.1 )專業的PHP整合開發工具

    WebStorm Mac版

    WebStorm Mac版

    好用的JavaScript開發工具

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具