javascript你不知道的This

来源:http://www.cnblogs.com/jiaoyu121/archive/2017/06/23/7069307.html
-Advertisement-
Play Games

《你不知道的javascript》這本書讀了有好幾遍了,似乎每一次讀都有新發現,有些內容並不是一下子可以弄懂的,每次讀似乎都能明白一些概念。再重讀一下this關鍵字。這個概念非常靈活,也非常難掌握,所以我覺得經常讀讀沒有壞處。期待javascript一桶江湖,這樣學習的成本就低啦!參考本書的第二部分 ...


《你不知道的javascript》這本書讀了有好幾遍了,似乎每一次讀都有新發現,有些內容並不是一下子可以弄懂的,每次讀似乎都能明白一些概念。
再重讀一下this關鍵字。這個概念非常靈活,也非常難掌握,所以我覺得經常讀讀沒有壞處。期待javascript一桶江湖,這樣學習的成本就低啦!
參考本書的第二部分的第一章,第二章。

this關鍵字是js中最最複雜的機制之一。他被自動定義到所有函數的作用域中。

在學習這個關鍵字的過程中似乎也走了很長時間的彎路。你要問我為什麼走了很長時間的彎路,關鍵的地方還是沒有對核心的概念徹底學習和領會,這一點和小學生學習新知識沒有任何區別。要想掌握this這個關鍵字,需要緊扣關鍵概念,不要憑空想象這到底是怎麼一回事。

關鍵概念:js中的函數在調用的時候,一定,一定,一定會綁定在一個對象上,在分析this關鍵字的時候,一定要知道函數在調用的時候這個對象到底是誰?。
切記:js中函數的調用和定義是沒有任何關係的,函數所綁定的對象直到他被調用的時候才能知道。

this關鍵字的不確定定是把雙刃劍,一是函數調用時的對象不確定性,是js中函數的使用具有很大靈活性,每個對象都可以借用其他函數來完成功能。二是這也造成了this學習的一些困擾。所以在學習的時候先要理解this關鍵字的優點,然後再去學習造成困擾的地方

首先看看第一段代碼
page 75

//註意只是定義了一個函數,並未調用,這時候函數是沒有綁定任何對象
function identify() {
    return this.name.toUpperCase();
}
//同上面的函數,但是這個函數內部有點複雜,如果下麵的代碼看不懂
//可以只看上面的函數
function speak() {
    var greeting = "Hello, I'm " + identify.call( this );
    console.log( greeting );
}

var me = { //定義了一個字面量對象
    name: "Kyle"
};

var you = {//定義了一個字面量對象
    name: "Reader"
};
//通過call方式把函數identify分別綁定到兩個對象上
//這時的this是指向me對象,和you對象
identify.call( me ); // KYLE  
identify.call( you ); // READER

//通過call方式把函數call分別綁定到兩個對象上
//這時的this是指向me對象,和you對象
speak.call( me ); // Hello, I'm KYLE
speak.call( you ); // Hello, I'm READER

在javascript中定義函數的時候,函數是不屬於任何對象的。這一點非常的關鍵,非常的關鍵,非常的關鍵。這是理解this關鍵字的第一個障礙。

this關鍵字在js函數定義的時候的不確定性使得js函數使用有極大的靈活性,任何對象都可以使用他。

this到底是什麼?

this的綁定和函數定義的位置沒有任何關係,只取決於函數調用的方式.
javascript中當一個函數被調用的時候,會創建一個活動記錄(有時也稱上下文)。這個記錄包括函數在哪裡被調用,函數的調用方法,傳入的參數。this就是記錄中的一個屬性。

這樣在學習javascript關鍵字的首要問題是要解決怎麼知道到函數的調用位置.

js對象綁定規則

每個js函數在調用的時候一定要找到一個對象,綁定以後才能使用。 這裡是理解了js函數的定義和調用的區別以後需要掌握的一個規模最龐大的概念,在js中一共有四種綁定方式.就我個人來看,綁定規則並不難,難點還是在js的函數作用域的理解. 尤其是預設綁定.這個綁定方式有極大的迷惑性。

預設綁定

這個是函數的獨立調用,也就是在一個函數直接調用的時候,似乎是沒有綁定到對象上的,但是根據前面的介紹,js中函數調用時必須要綁定到一個對象上。
看下麵代碼 page 83

  function foo() { //這是函數的定義位置
    console.log( this.a );
}

  var a = 2;//這個變數定義的含義是什麼呢?僅僅是賦值給a嗎?

  foo(); // 2  //這是函數的調用位置。為什麼會列印出2呢?

很多函數都是這麼調用的,照貓畫虎也可以寫出來,但是理解了具體的含義就不一樣了。
foo這個函數定義在全局作用域中(window作用域中),巧合的是他的調用也是在全局作用域中,註意這僅僅是巧合,巧合。 那麼foo()調用的時候為什麼會列印出變數 a的值呢?儘管使用了var這個關鍵字,但是分析作用域可以知道,a這個變數實際是全局變數,說的再明白一點,a實際是window這個全局對象的一個屬性,2是這個屬性的屬性值。
foo()調用的時候是一絲不掛的全裸狀態,僅僅是函數本身,沒有任何修飾符,這個時候他也沒有任何函數包裹,處在全局作用域下麵,所以foo()裡面的this是指向全局對象的,當要列印this.a的時候,尋找foo()調用位置會找到全局作用域,找全局作用域的屬性this.a的時候會列印出2這個屬性值。

我們在使用setTimeout,setInterval函數的時候,實際這兩個函數就是一絲不掛的,同樣綁定在window對象上。

隱式綁定

函數在調用的時候被添加了修飾符。看下麵這個代碼
page 85

  function foo() { //定義在全局作用下的函數,僅僅是定義,不是調用位置
    console.log( this.a );
}

var obj = { //定義一個對象
    a: 2,
    foo: foo
};

obj.foo(); // 2  給foo()函數找了一個對象,this就指向這個對象了

這是最常見的方式了,如果不寫前面的obj是不是就是上面的預設綁定了?

隱式丟失
經常在js代碼的嵌套回調函數中看到在外層函數開始的一句

   var  that=this; //這是什麼含義

或許你已經會用了,但是理解了其中意義用起來會更加得心應手啊

看下麵段代碼.這段代碼其實以前我也不太理解,問題還是沒有徹底領悟js函數定義和調用之間是沒有關係的這一點。
page 86

function foo() { //定義了一個函數
    console.log( this.a );
}

var obj = { //定義了一個對象字面量
    a: 2,
    foo: foo  //函數作為對對象的屬性
};

var bar = obj.foo; //把obj對象的函數foo屬性賦值給bar變數
//這裡就是理解這個問題的關鍵,如果你現在認為調用bar()的時候綁定的對象
//是obj那就完全搞錯了。這個時候僅僅是把函數foo賦值給了var變數,
//並沒有把對象也給bar變數,因為這裡還不是foo()函數的調用位置,現在
//foo函數還沒有綁定對象,那麼調用bar()的時候對象到底是誰?不知道。
//調用的時候才知道。

var a = "oops, global"; // 任然是全局對象的屬性
bar(); // "oops, global" 這裡執行的是預設綁定,this就是去全局對象啦

下麵這段代碼就是使用var that=this的場景
在使用回調函數的時候要留心。js中函數是一等對象,可以作為另一個函數的參數傳入函數。 問題就出在這裡了,函數一旦作為實參代替形參的時候,實際也執行了和上面代碼一樣的賦值過程,實際只是傳遞了函數本身,原先的對象就沒有了。

page 86

function foo() { //定義一個函數
    console.log( this.a );
}

function doFoo(fn) { //fn是形參
    // 如果函數作為實參傳入相當於代碼 var fn=obj.foo
    //和上面一段代碼是完全一樣的,只是函數本身,並沒有綁定任何對象

    fn(); // 在這裡調用的時候,由於fn只代表foo()函數,被綁定到全局對象上了
}

var obj = {
    a: 2,
    foo: foo
};

var a = "oops, global"; // `a` also property on global object

doFoo( obj.foo ); // "oops, global"不要被obj.foo迷惑了
//沒有實際執行函數的調用,此時obj.foo僅僅代表沒有綁定任何對象的函數

//這個代碼塊看著眼熟麽?這就是javascript中回調函數的樣子,當
//一個函數作為參數傳遞進另一個函數的時候,這個參數函數就找不到自己綁定的對象是誰了,
//所以就預設綁定到全局對象上了。但是我們既然在一個函數里調用另一個函數,肯定是要用這個函數操作當前的對象,那麼既然找不到了,我們就手動給他指定一個對象吧。這就是為什麼要使用
//var  that=this的原因。我覺得理解這個概念,js的功力至少會增加5%

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 用python3.4讀取Excel中的數據並繪圖,一個簡單的實現。 ...
  • 主線程:執行主方法的線程,就叫做主線程 單線程程式:程式從mani開始從上到下依次運行 程式從main方法開始運行,JVM運行main方法,會找操作系統 開闢一條通向cpu的執行路徑,cpu可以通過這條路徑來執行main方法 這條路徑有一個名字叫主(main)線程 創建線程方式一繼承Thread類 ...
  • 想要瞭解介面我們要先知道抽象類。那麼什麼是抽象類呢? 問題描述:生活中我們有很多的對象是無法具體描述的,比如說:我們可以說四邊形有四條邊。或者具體點說就是矩形兩邊對稱且相等,正方形四邊對稱且相等。但是對於普通的圖形而言就很難具體描述了。轉換成Java語言就是說:對於一個很具體的類我們可以很方便的定義 ...
  • 轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/72933882 本文出自 "【趙彥軍的博客】" 使用fiddler抓包時,會看到左側按照順序顯示session,並且前邊有個圖標,但通常,不知道圖標是什麼意思。 參考官方文檔: "UI ...
  • 一 概述 1.網路模型 OSI(Open System Interconnection,開放式系統互聯)模型,是對網路系統結構的概括,將網路分為七層:應用層、表示層、會話層、傳輸層、網路層、數據鏈路層、物理層。 2.IP協議 網路層協議,規定了在互聯網上確定與尋找電腦的規則。 3.TCP協議 傳輸 ...
  • 入園第一天 ...
  • 在整個項目站點下的__init__.py 文件里(即和setting.py在同一個文件下)寫入以下代碼: 需要提前安裝pymysql模塊,相當於Python2中的MySQLdb模塊。 ...
  • $("#totalTb").datagrid({ columns: [[ { field: 'ENTITY_ACTNAME', title: '活動名稱', width: 120, align: "left", halign: 'center' }, { field: 'ACT_RATE', tit ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...