Javascript基礎Day4

来源:https://www.cnblogs.com/wpdh/archive/2022/07/31/16537946.html
-Advertisement-
Play Games

Javascript基礎Day4 函數(下) 作用域(重點) 什麼是作用域,就是一個變數可以生效的範圍 變數不是在所有地方都可以使用的,而這個變數的使用範圍就是作用域 全局作用域 整個頁面起作用,在<script>內都能訪問到; 在全局作用域中有全局對象window,代表一個瀏覽器視窗,由瀏覽器創建 ...


Javascript基礎Day4

函數(下)

作用域(重點)

  • 什麼是作用域,就是一個變數可以生效的範圍

  • 變數不是在所有地方都可以使用的,而這個變數的使用範圍就是作用域

 

全局作用域

  • 整個頁面起作用,在<script>內都能訪問到;

  • 在全局作用域中有全局對象window,代表一個瀏覽器視窗,由瀏覽器創建,可以直接調用;

  • 全局作用域中聲明的變數和函數,會作為window對象的屬性和方法保存;

  • 變數在函數外聲明,即為全局變數,擁有全局作用域。

        var a = 123;//全局變數    
        function fn() {
            console.log(a);//123    
        }    
        fn();    
        console.log(a);//123

 

局部作用域

  • 局部作用域內的變數只能在函數內部使用,所以也叫函數作用域;

  • 變數在函數內聲明,即為局部變數,擁有局部作用域。

        function fn() {
            var b = 456;//局部變數        console.log(b);//456    
        }    
        fn();    
        console.log(b);//b is not defined

註:可以直接給一個未聲明的變數賦值(全局變數),但不能直接使用未聲明的變數!因為局部變數只作用於函數內,所以不同的函數可以使用相同名稱的變數。當全局與局部有同名變數的時候,訪問該變數將遵循 "就近原則"。

變數的生命周期

  • 全局變數在頁面打開時創建,在頁面關閉後銷毀。

  • 局部變數在函數開始執行時創建,函數執行完後局部變數會自動銷毀。

 

變數使用規則(重點)

  • 有了作用域以後,變數就有了使用範圍,也就有了使用規則

  • 變數使用規則分為兩種,訪問規則賦值規則

 

訪問規則

  • 當我想獲取一個變數的值的時候,我們管這個行為叫做 訪問

  • 獲取變數的規則:

    • 首先,在自己的作用域內部查找,如果有,就直接拿來使用

    • 如果沒有,就去上一級作用域查找,如果有,就拿來使用

    • 如果沒有,就繼續去上一級作用域查找,依次類推

    • 如果一直到全局作用域都沒有這個變數,那麼就會直接報錯(該變數 is not defined)

    var num = 100
        function fn() {  
            var num2 = 200    
            function fun() {    
                var num3 = 300        
                console.log(num3) // 自己作用域內有,拿過來用    
                console.log(num2) // 自己作用域內沒有,就去上一級,就是 fn 的作用域裡面找,發現有,拿過來用    
                console.log(num) // 自己這沒有,去上一級 fn 那裡也沒有,再上一級到全局作用域,發現有,直接用    
                console.log(a) // 自己沒有,一級一級找上去到全局都沒有,就會報錯  
            }    fun()
        }​fn()
  • 變數的訪問規則 也叫做 作用域的查找機制

  • 作用域的查找機制只能是向上找,不能向下找

        function fn() {  
            var num = 100
            }
        fn()​
        console.log(num) // 發現自己作用域沒有,自己就是全局作用域,沒有再上一級了,直接報錯

     

賦值規則

  • 當你想給一個變數賦值的時候,那麼就先要找到這個變數,在給他賦值

  • 變數賦值規則:

    • 先在自己作用域內部查找,有就直接賦值

    • 沒有就去上一級作用域內部查找,有就直接賦值

    • 在沒有再去上一級作用域查找,有就直接賦值

    • 如果一直找到全局作用域都沒有,那麼就把這個變數定義為全局變數,在給他賦值

        function fn() {  
            num = 100
        }fn()​
        // fn 調用以後,要給 num 賦值
        // 查看自己的作用域內部沒有 num 變數
        // 就會向上一級查找
        // 上一級就是全局作用域,發現依舊沒有
        // 那麼就會把 num 定義為全局的變數,併為其賦值
        // 所以 fn() 以後,全局就有了一個變數叫做 num 並且值是 100console.log(num) 
        // 100

 

常見事件

  • 瀏覽器事件

    • onload 載入完畢

    • onscroll 瀏覽器滾動事件

    • onresize 瀏覽器視窗改變事件

  • 滑鼠事件

    • onclick :點擊事件

    • ondblclick :雙擊事件

    • oncontextmenu`: 右鍵單擊事件

    • onmousedown :滑鼠左鍵按下事件

    • onmouseup :滑鼠左鍵抬起事件

    • onmousemove :滑鼠移動

    • onmouseover :滑鼠移入事件

    • onmouseout :滑鼠移出事件

    • onmouseenter :滑鼠移入事件(不冒泡)

    • onmouseleave :滑鼠移出事件(不冒泡)

    • onselectstart:選中事件(不被 input 和 textarea 標簽支持 )

    • onselect:選中事件(支持 input 和 textarea 標簽)

  • 鍵盤事件

    • onkeydown 鍵盤按下事件

    • onkeyup 鍵盤釋放事件

    • onkeypress 產生可列印字元事件

    註:鍵盤事件綁定的位置,要麼是document,要麼是輸入框

  • 觸摸事件(移動端)

    • ontouchstart 觸摸開始

    • ontouchmove 觸摸移動

    • ontouchend 觸摸結束

  • 表單事件

    • onchange 表單改變事件(失去焦點時觸發)

    • oninput 表單輸入事件(輸入時觸發)

    • onsubmit 表單提交事件(點擊submit時觸發)

    • onfocus :獲得焦點事件

    • onblur :失去焦點事件

  • 其他事件

    • ontransitionend 過渡結束的時候觸發

    • onanimationend 動畫結束的時候觸發

自執行函數

    要執行一個函數,我們必須要有方法定義函數、引用函數。​
    匿名函數如何調用?​
    匿名自執行函數,也叫立即執行函數(IIFE)。​
    (function () {    
    console.log(123);
    })();​
    小括弧能把我們的表達式組合分塊,並且每一塊都有一個返回值,這個返回值實際上就是小括弧中表達式的返回值。
    ​自執行函數的好處:獨立的作用域,不會污染全局環境!​
    
    傳參:(function (a,b) {    
    console.log(a + b);
    })(2,3);​
    
    常見形式:(function () {    
    console.log(11);
    })();​
    
    (function(){  
    console.log(22);
    }());​
    
    !function() {    
    console.log(33);
    }();​
    
    +function() {    
    console.log(55);
    }();
    
    ​-function() {    
    console.log(66);
    }();​
    
    ~function() {   
    console.log(77);
    }();

 

遞歸函數

  • 什麼是遞歸函數

  • 在編程世界裡面,遞歸就是一個自己調用自己的手段

  • 遞歸函數: 一個函數內部,調用了自己,迴圈往複

  • 一般來說,遞歸需要有邊界條件、遞歸前進段和遞歸返回段。

  • 當邊界條件不滿足時,遞歸前進;當邊界條件滿足時,遞歸返回。

        // 下麵這個代碼就是一個最簡單的遞歸函數
        // 在函數內部調用了自己,函數一執行,就調用自己一次,在調用再執行,迴圈往複,沒有止盡function fn() {  fn()}fn()
  • 其實遞歸函數和迴圈很類似

  • 需要有初始化,自增,執行代碼,條件判斷的,不然就是一個沒有盡頭的遞歸函數,我們叫做 死遞歸

 

簡單實現一個遞歸

  • 我們先在用遞歸函數簡單實現一個效果

  • 需求: 求 1 至 5 的和

    • 先算 1 + 2 得 3

    • 再算 3 + 3 得 6

    • 再算 6 + 4 得 10

    • 再算 10 + 5 得 15

    • 結束

  • 開始書寫,寫遞歸函數先要寫結束條件(為了避免出現 “死遞歸”)

        function add(n) {  
            // 傳遞進來的是 1  
            // 當 n === 5 的時候要結束  
            if (n === 5) {    
                return 5  
            }}​
            add(1)
  • 再寫不滿足條件的時候我們的遞歸處理

            function add(n) {  
            // 傳遞進來的是 1  
            // 當 n === 5 的時候要結束  
            if (n === 5) {    
                    return 5  
                } else {    
                    // 不滿足條件的時候,就是當前數字 + 比自己大 1 的數字    
                    return n + add(n + 1)  
                }}
            add(1)
  • 老王有四個子女,老四比老三小2歲,老三比老二小2歲,老二比老大小2歲,老大現在16歲,問老四幾歲?  

    function countAge(who) {        
        if (who == 1) {            
            return 16;        } 
        else {            
            return countAge(who - 1) - 2;        
        }    
    }    
alert(countAge(4)); // 10

註:遞歸函數在運行的時候,每調用一次函數就會在記憶體中開闢一塊空間,記憶體消耗較大,註意防止棧溢出。

遞歸演算法一般用於解決三類問題:  

​ 1.數據的定義是按遞歸定義的; 

​ 2.問題解法按遞歸演算法實現;  

​ 3.數據的結構形式是按遞歸定義的。

構造函數(瞭解)

構造函數:用於創建特定類型的對象。

JS內部構造函數:Object、Number、String、Array、Function、Boolean等等...

當任意一個普通函數用於創建一類對象,並通過new操作符來調用時它就可以作為構造函數。

構造函數一般首字母大寫。

簡單對象(掌握)

  • 對象是一個複雜數據類型

  • 對象是一組無序的鍵值對,是帶有屬性和方法的集合。

  • 通俗講,對象就是無序的數據集合。

  • 屬性是與對象相關的值,方法是能夠在對象上執行的動作。

  • 對象的作用:用於在單個變數中存儲多個值。

創建一個對象

  • 字面量的方式創建一個對象

        var obj = { 鍵:值, 鍵:值 ...... };
        鍵:一般用雙引號引起來(不用引號也可以)
        值:可以是任意類型的數據
        var obj = {    
            name: '小錯',    
            age: 18,    
            sayHi: function (){        
                alert('hi,大家好');    
            }}
  • 內置構造函數的方式創建對象

        var obj2 = new Object();
        obj2.name = '小錯';
        obj2.age = 18;
        obj2.sayHi = function (){    
            alert('hi,大家好');
        }
        console.log( obj2.name );
        obj2.sayHi( );
  • 操作對象

        訪問對象成員:    
        1. 對象.屬性   
           對象.方法()    
        2. 對象[變數或字元串]​刪除屬性:    
        delete obj.attr;​遍歷對象:{}    
        for / in 迴圈    
        for (var key in obj){        
            console.log( obj[key] );    
        }

    {}和new創建對象的對比(瞭解)

    字面量的優勢:

    它的代碼量更少,更易讀;它可以強調對象就是一個簡單的可變的散列表,而不必一定派生自某個類;對象字面量運行速度更快,因為它們可以在解析的時候被優化——它們不需要"作用域解析"!因為存在我們創建了一個同名構造函數Object()的可能,所以當我們調用Object()的時候,解析器需要順著作用域鏈從當前作用域開始查找,如果在當前作用域找到了名為Object()的函數就執行,如果沒找到,就繼續順著作用域鏈往上找,直到找到全局Object()構造函數為止

    構造函數的優勢:

    Object()構造函數可以接收參數,通過這個參數可以把對象實例的創建過程委托給另一個內置構造函數(Number()、String()等),並返回另一個對象實例。使用自定義構造函數創建對象,可以通過傳參添加屬性和方法,當需要定義的同類對象較多時,節省了定義對象的代碼量,並且使對象屬性和方法的結構更加清晰

     

  • 數據類型之間存儲的區別(重點)

    • 既然我們區分了基本數據類型和複雜數據類型

    • 那麼他們之間就一定會存在一些區別

    • 他們最大的區別就是在存儲上的區別

    • 我們的存儲空間分成兩種

    • 棧: 主要存儲基本數據類型的內容

    • 堆: 主要存儲複雜數據類型的內容

     

    基本數據類型在記憶體中的存儲情況

    • var num = 100,在記憶體中的存儲情況

    • 直接在 棧空間 內有存儲一個數據

     

    複雜數據類型在記憶體中的存儲情況

    • 下麵這個 對象 的存儲

          var obj = {  
              name: 'Jack',  
              age: 18,  
              gender: '男'
          }
    • 複雜數據類型的存儲

      1. 在堆裡面開闢一個存儲空間

      2. 把數據存儲到存儲空間內

      3. 把存儲空間的地址賦值給棧裡面的變數

    • 這就是數據類型之間存儲的區別

     

    數據類型之間的賦值

    • 基本數據類型之間的賦值

              var num = 10var 
              num2 = num​
              num2 = 200​
              console.log(num) 
              // 10
              console.log(num2) 
              // 200
      • 相當於是把 num 的值複製了一份一摸一樣的給了 num2 變數

      • 賦值以後兩個在沒有關係

    • 複雜數據類型之間的賦值

          var obj = {  
              name: 'Jack'
          }
          var obj2 = obj​
          obj2.name = 'Rose'​
          console.log(obj.name) 
          // Roseconsole.log(obj2.name) 
          // Rose
      • 因為複雜數據類型,變數存儲的是地址,真實內容在 堆空間 記憶體儲

      • 所以賦值的時候相當於把 obj 存儲的那個地址複製了一份給到了 obj2 變數

      • 現在 obj 和 obj2 兩個變數存儲的地址一樣,指向一個記憶體空間

      • 所以使用 obj2 這個變數修改空間內的內容,obj 指向的空間也會跟著改變了

    數據類型之間的比較

    • 基本數據類型是 之間的比較

          var num = 1var 
          str = '1'​
          console.log(num == str) 
          // true
    • 複雜數據類型是 地址 之間的比較

          var obj = { name: 'Jack' }
          var obj2 = { name: 'Jack' }​
          console.log(obj == obj2) // false
      • 因為我們創建了兩個對象,那麼就會在 堆空間 裡面開闢兩個存儲空間存儲數據(兩個地址)

      • 雖然存儲的內容是一樣的,那麼也是兩個存儲空間,兩個地址

      • 複雜數據類型之間就是地址的比較,所以 objobj2 兩個變數的地址不一樣

      • 所以我們得到的就是 false

 

函數的參數

  • 函數的參數也是賦值的,在函數調用的時候,實參給行參賦值

  • 和之前變數賦值的規則是一樣的

  • 函數傳遞基本數據類型

        function fn(n) {  
            n = 200  
            console.log(n) 
            // 200
        }​
        var num = 100fn(num)
        console.log(num) 
            // 100
    • 和之前變數賦值的時候一樣,在把 num 的值複製了一份一摸一樣的給到了函數內部的行參 n

    • 兩個之間在沒有任何關係了

  • 函數傳遞複雜數據類型

        function fn(o) {  
            o.name = 'Rose'  
            console.log(o.name) 
            // Rose
        }​
        var obj = {  
            name: 'Jack'
        }
        fn(obj) 
        //所傳遞的就是obj的引用地址console.log(obj.name) 
        // Rose
    • 和之前變數賦值的時候一樣,把 obj 記憶體儲的地址複製了一份一摸一樣的給到函數內部的行參 o

    • 函數外部的 obj 和函數內部的行參 o,存儲的是一個地址,指向的是一個存儲空間

    • 所以兩個變數操作的是一個存儲空間

    • 在函數內部改變了空間內的數據

    • obj 看到的也是改變以後的內容

js常見錯誤類型

SyntaxError :語法錯誤

    // 1) 變數名不符合規範var 1       
    // Uncaught SyntaxError: Unexpected numbervar 1a       
    // Uncaught SyntaxError: Invalid or unexpected token// 2) 給關鍵字賦值function = 5     
    // Uncaught SyntaxError: Unexpected token =

ReferenceError :引用錯誤(要用的變數沒找到)

    // 1) 引用了不存在的變數a()       
    // Uncaught ReferenceError: a is not definedconsole.log(b)     
    // Uncaught ReferenceError: b is not defined// 2) 給一個無法被賦值的對象賦值console.log("abc") = 1   
    // Uncaught ReferenceError: Invalid left-hand side in assignment

TypeError: 類型錯誤(調用不存在的方法)

    // 1) 調用不存在的方法123()        
    // Uncaught TypeError: 123 is not a functionvar o = {}o.run()        
    // Uncaught TypeError: o.run is not a function// 2) new關鍵字後接基本類型var p = new 456      
    // Uncaught TypeError: 456 is not a constructor

RangeError: 範圍錯誤(參數超範圍)

    // 1) 數組長度為負數[].length = -5      
    // Uncaught RangeError: Invalid array length// 2) Number對象的方法參數超出範圍var num = new Number(12.34)console.log(num.toFixed(-1))   
    // Uncaught RangeError: toFixed() digits argument must be between 0 and 20 at Number.toFixed
    // 說明: toFixed方法的作用是將數字四捨五入為指定小數位數的數字,參數是小數點後的位數,範圍為0-20.

 


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

-Advertisement-
Play Games
更多相關文章
  • Music Tag Editor 中文版是一款macOS平臺的音頻標簽管理工具,支持UNICODE,軟體帶有PLS/M3U列表生成器,還可以生成XML/TXT/CSV格式的播放列表,通過它用戶可以快速修改音樂文件的tag信息、創建播放列表,另外,軟體自帶播放器,可以播放常見的音頻文件。 詳情:Mus ...
  • PDFelement Pro Mac是一款可以幫助用戶編輯PDF的工具,其設計的功能針對中小型用戶開發,支持常規的編輯、修改、操作,並且可以實現PDF文件轉換功能,您可以將word、Excel等office文件轉換為PDF文件保存,讓您可以擁有一款簡單、高效的PDF辦公軟體。 詳情:Wondersh ...
  • SoundSource 5 for Mac是一款優質的音頻控制軟體,可讓您直接從菜單欄調整輸入,輸出和音效設備以及音量設置。啟用輸入設備的軟播放到您想要的輸出,這樣您就可以聽到通過任何麥克風或其他來源發出的聲音。 詳情:SoundSource 5 for Mac(音頻控制工具) 功能介紹 1、快速訪 ...
  • 上篇文章講到使用MySQL的Explain命令可以分析SQL性能瓶頸,優化SQL查詢,以及查看是否用到了索引。 我們都知道創建索引可以提高查詢效率,但是具體該怎麼創建索引? 哪些欄位適合創建索引? 哪些欄位又不適合創建索引? 本文跟大家一塊學習一下如何創建合適資料庫索引。 ...
  • 使用flink的時候難免和redis打交道,相信大家都使用過flink-connector-redis來處理,但是當我想要使用RedisSink寫入集群時,發現居然不支持使用密碼,於是有了這篇筆記。 ...
  • 2016年是對話式設計之年。消息應用正以驚人的好評度和參與率,占領世界和app store的排行榜。每個社區產品、應用市場、點播服務、約會應用、社交游戲和電商產品,為了提高好評度、參與率和銷量,都已經或即將加入消息功能。 有大量關於對話式UI的討論,還有這種人機對話模式如何通過簡單的指令和文字反饋( ...
  • 視頻地址:https://learning.dcloud.io/#/?vid=0 開發工具:XbuilderX 官方教程:https://cn.vuejs.org/v2/guide/ 序言 Vue.js :漸進式JavaScript框架 Vue.js優點 1.體積小 壓縮後33K; 2.更高的運行效 ...
  • 1.shift+alt+f 格式化代碼(vscode) 2.css的複合選擇器 後代選擇器:選後代(不一定是兒子) 空格隔開 如ol li{樣式聲明} 更好地選擇想要的標簽 也可以用class表示 如 .nav.li.a 子選擇器 >親兒子 並集選擇器 逗號 div,p{樣式聲明} 最後一個選擇器 ...
一周排行
    -Advertisement-
    Play Games
  • 1、預覽地址:http://139.155.137.144:9012 2、qq群:801913255 一、前言 隨著網路的發展,企業對於信息系統數據的保密工作愈發重視,不同身份、角色對於數據的訪問許可權都應該大相徑庭。 列如 1、不同登錄人員對一個數據列表的可見度是不一樣的,如數據列、數據行、數據按鈕 ...
  • 前言 上一篇文章寫瞭如何使用RabbitMQ做個簡單的發送郵件項目,然後評論也是比較多,也是準備去學習一下如何確保RabbitMQ的消息可靠性,但是由於時間原因,先來說說設計模式中的簡單工廠模式吧! 在瞭解簡單工廠模式之前,我們要知道C#是一款面向對象的高級程式語言。它有3大特性,封裝、繼承、多態。 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 介紹 Nodify是一個WPF基於節點的編輯器控制項,其中包含一系列節點、連接和連接器組件,旨在簡化構建基於節點的工具的過程 ...
  • 創建一個webapi項目做測試使用。 創建新控制器,搭建一個基礎框架,包括獲取當天日期、wiki的請求地址等 創建一個Http請求幫助類以及方法,用於獲取指定URL的信息 使用http請求訪問指定url,先運行一下,看看返回的內容。內容如圖右邊所示,實際上是一個Json數據。我們主要解析 大事記 部 ...
  • 最近在不少自媒體上看到有關.NET與C#的資訊與評價,感覺大家對.NET與C#還是不太瞭解,尤其是對2016年6月發佈的跨平臺.NET Core 1.0,更是知之甚少。在考慮一番之後,還是決定寫點東西總結一下,也回顧一下.NET的發展歷史。 首先,你沒看錯,.NET是跨平臺的,可以在Windows、 ...
  • Nodify學習 一:介紹與使用 - 可樂_加冰 - 博客園 (cnblogs.com) Nodify學習 二:添加節點 - 可樂_加冰 - 博客園 (cnblogs.com) 添加節點(nodes) 通過上一篇我們已經創建好了編輯器實例現在我們為編輯器添加一個節點 添加model和viewmode ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...
  • 類型檢查和轉換:當你需要檢查對象是否為特定類型,並且希望在同一時間內將其轉換為那個類型時,模式匹配提供了一種更簡潔的方式來完成這一任務,避免了使用傳統的as和is操作符後還需要進行額外的null檢查。 複雜條件邏輯:在處理複雜的條件邏輯時,特別是涉及到多個條件和類型的情況下,使用模式匹配可以使代碼更 ...
  • 在日常開發中,我們經常需要和文件打交道,特別是桌面開發,有時候就會需要載入大批量的文件,而且可能還會存在部分文件缺失的情況,那麼如何才能快速的判斷文件是否存在呢?如果處理不當的,且文件數量比較多的時候,可能會造成卡頓等情況,進而影響程式的使用體驗。今天就以一個簡單的小例子,簡述兩種不同的判斷文件是否... ...
  • 前言 資料庫併發,數據審計和軟刪除一直是數據持久化方面的經典問題。早些時候,這些工作需要手寫複雜的SQL或者通過存儲過程和觸發器實現。手寫複雜SQL對軟體可維護性構成了相當大的挑戰,隨著SQL字數的變多,用到的嵌套和複雜語法增加,可讀性和可維護性的難度是幾何級暴漲。因此如何在實現功能的同時控制這些S ...