JavaScript篇 深入理解JavaScript函數

来源:https://www.cnblogs.com/mokeycode/archive/2019/04/13/10700805.html
-Advertisement-
Play Games

JavaScript中的函數 1. 函數的定義 兩種定義形式: 通過函數定義表達式來定義 通過函數聲明語句來定義 通過函數定義表達式來定義 通過函數聲明語句來定義 函數聲明語句定義一個函數 函數定義表達式定義一個函數 tips:以表達式方式定義的函數(特別適合用來定義那些只會用到一次的函數),函數名 ...


JavaScript中的函數

1. 函數的定義

  • 兩種定義形式: 
    • 通過函數定義表達式來定義 
    • 通過函數聲明語句來定義

函數聲明語句定義一個函數

//計算階乘的遞歸函數

function factorial(x){
    if (x<=1) return 1;
    return x*factotial(x-1);
}

函數定義表達式定義一個函數

var s= function sum(x,y){
    return x+y;
}

tips:以表達式方式定義的函數(特別適合用來定義那些只會用到一次的函數),函數名是可選的,
也就可以直接寫成這樣

var s= function(x,y){
    return x+y;
}

2.函數命名

  • 函數的名稱通常是動詞或者以動詞為首碼的片語 如:funciton saveMessage(){}
  • 函數名的第一個字元通常為小寫
  • 當我們命名的函數名比較長時,一種是駝峰式命名 如:function readSystemFile(){}
    另一種是以下劃線分割單詞,如:function make_products_iPhones(){}
  • 有一些函數是用作內部函數或者私有函數的,通常以一條下劃線為首碼。 如: _login()

3.函數的調用

  • 普通的函數調用

example:

printprops({x:1})
var total = distance(0,1,2)+ distance(3,4,5)
var probability = factorial(5)/factoral(10)
  • 對象方法的調用

概念:如果函數表達式是一個屬性訪問表達式(即該函數是一個對象的屬性或者數組的一個函數),
那麼該調用表達式就是一個方法調用表用表達式。
example:

//定義一個對象
    var person = {  
    name: lihua ,  
    age:  18 ,  
    sex:  女 ,  
    send: function(){//返回 person的name、age、sex
            this.message = this.name + this.age + this.age;
        } 
    };
    person.send();//這條語句就是函數的方法調用
    person.message; //得到name、age、sex相關信息

tips:
1.函數返回的值倘若是因為解釋器到達結尾,返回值就是undefined;倘若函數返回是因為解釋器執行到一條return語句,
則返回return語句後面的值;如果return語句後面沒有值則返回undefined。
2.在ECMAScript3和在非嚴格模式下的ECMAScript5的函數調用規定中,this的值(調用上下文)的值是全局對象,但是在
嚴格模式下this的值卻是undefined,因此可也用this來判斷當前環境是否為嚴格模式,此外ECMAScript2015 (簡稱es6)嚴格模式請參考以下地址。
ECMAScipt的第六個版本  https://developer.mozilla.org/zh-CN/
3.方法調用和普通的函數調用的一個重要區別就是:調用上下文(即this的值),通常this關鍵字指向成為調用上下文的對象,
屬性訪問表達式:對象名.方法名(通常使用.運算符訪問屬性)或者"[]"進行屬性訪問操作。(this關鍵字的相關內容是十分重要的)
更多this相關內容請參看此鏈接

  • 構造函數的調用 

構造函數就是用來初始化先創建的對象,通常使用關鍵字new來調用構造函數,當使用new關鍵字來調用構造函數的時候就會自動
創建一個新的的空對象,而構造函數只需要初始化這個新對象的狀態(屬性和方法),調用構造函數的話,新的對象的原型(prototype)等於
構造函數的原型(prototype)屬性,由此引出一個特性:通過同一個構造函數創建的所有對象都繼承同一個相同的對象。

凡是沒有形參的構造函數都可以省略圓括弧,以下兩行代碼是等價的。
var fn = new Object();
var fn = new Object;

tips:
1.構造函數通常不使用return關鍵字,進行初始化新對象,執行完函數體,就調用構造函數表達式的計算結果作為新對象的值,顯示返回。
2.倘若構造函數使用return語句返回一個對象,那麼調用表達式的值就是這個對象,而不是this指向的對象。
3.構造函數里沒有顯式調用return時,預設是返回this對象,也就是新創建的實例對象。
4.return的是五種簡單數據類型:String,Number,Boolean,Null,Undefined。這種情況下,忽視return值,依然返回this對象

  • 間接調用
    JavaScript中的函數也是對象,所以函數對象也可以包含方法。函數的間接調用用到的call()和apply()方法。
    這兩個方法都能顯示指定調用所需的this的值,這就引出一個特性:任何函數都可以作為對象的方法來調用,
    哪怕這個函數不是那個對象的方法。(這也就是在實際開發中我們也會常用這兩個方法的原因之一) 

1.call()方法調用一個函數, 其具有一個指定的this值和分別地提供的參數(參數的列表) this的值並不一定就是該函數執行真正的this值,在非嚴格模式下,倘若this的值指向nullundefined的話
會自動指向全局對象(瀏覽器中就是window對象),同時值為原始值(數字,字元串,布爾值)的this會指向該原始值的自動包裝對象。
2.apply()方法調用一個具有給定this值的函數,以及作為一個數組(或類似數組對象)提供的參數。
為this指定一個對象,使用apply時只需要寫一次這個方法然後再另一個對象中繼承它,繼而不用在這個新的對象重新來寫它。

tips:call()方法的作用和 apply() 方法類似,區別就是call()方法接受的是參數列表,而apply()方法接受的是一個參數數組。

4.函數中的形參與實參

  • 可選的形參
  • 可變長的實參列表:實參對象 arguments 它是一個類數組對象,通過數字下表就能夠訪問傳入函數的實參值,它包含length屬性,讓函數可以操作任意數量的實參。 
  • callee和caller屬性
    callee屬性指代當前正在執行的函數,caller指代調用當前正在執行的函數的函數,它可以訪問棧。而callee可以來遞歸調用自身。

5.函數的閉包(!important)

  • 概念:通俗地講函數的閉包就是在一個函數內部定義另一個函數,而這個內部的函數(子函數)可以調用包裹它的函數(父函數等、"爺爺、太爺爺...")的變數。
    也可以認為閉包就是能夠讀取其他函數內部變數的函數。
  • 變數作用域:
    全局變數:任何函數內部都可以訪問全局作用域
    局部變數:在函數外部無法讀取變數 

tips
javascript是沒有像Java、C++那樣用一對“{}”括起來的塊級作用域,但是在es6中可以使用let關鍵字實現塊級作用域。

  • 詞法作用域:變數的作用域是在定義時決定而不是執行時決定,也就是說詞法作用域取決於源碼,通過靜態分析就能確定,因此詞法作用域也叫做靜態作用域。
    with和eval除外,所以只能說JS的作用域機制非常接近詞法作用域(Lexical scope)。
var scope = "global scope";  
function checkScope(){
    var scope = "local scope";
    function f(){return scope;}  
    return f();
}
checkScope();  //輸出可以得到 local scope
  • 閉包的用途
    i. 讀取函數內部的變數、函數嵌套函數
    ii. 讓這些變數的值始終保持在記憶體中(全局變數的值不會在被函數調用過後自動清除,由GC回收)
    iii. 避免全局變數的污染、讓私有成員存在 

  • 閉包的註意事項
    i. 由於閉包會使得函數中的變數都被保存在記憶體中,記憶體消耗很大,所以不能濫用閉包,否則會造成網頁的性能問題,在IE中可能導致記憶體泄露
    解決方法是,在退出函數之前,將不使用的局部變數全部刪除。
    ii. 閉包會在父函數外部,改變父函數內部變數的值。所以,如果你把父函數當作對象(object)使用,把閉包當作它的公用方法(Public Method),
    把內部變數當作它的私有屬性(private value),這時一定要小心,不要隨便改變父函數內部變數的值。
    以下例子來檢驗自己是否已經掌握了閉包的運行機制。
    example 0ne:

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      return function(){
        return this.name;
      };

    }

  };

  alert(object.getNameFunc()());

example Two:

  var name = "The Window";

  var object = {
    name : "My Object",

    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };

    }

  };

  alert(object.getNameFunc()());

6.函數的屬性、方法以及構造函數

  • length屬性
    argument.length屬性表示傳入函數的實參的個數,而函數本身的length屬性則有不同含義,它表示函數定義時的實際形參個數。
  • prototype(原型)屬性
    這個屬性指向對象的引用,而這個對象就被稱為原型對象(prototype object),每個函數都包含這個屬性,都包含不同的原型對象;
    在JavaScript中每個函數都有一個特殊的屬性叫作原型(prototype)
function doSomething(){}
console.log(doSomething.prototype);
-----------------------------------  
結果:  這就是 原型對象
{
 constructor: ƒ doSomething(), //構造函數
  /* 這些又是這個構造函數裡面的方法或者屬性 
    arguments: null
    caller: null
    length: 0
    name: "doSomething"
    prototype: {constructor: ƒ} 構造函數的原型屬性
     __proto__: ƒ ()*/

 __proto__: { //原型屬性
     constructor: ƒ Object(),
     hasOwnProperty: ƒ hasOwnProperty(),
     isPrototypeOf: ƒ isPrototypeOf(),
     propertyIsEnumerable: ƒ propertyIsEnumerable(),
     toLocaleString: ƒ toLocaleString(),
     toString: ƒ toString(),
     valueOf: ƒ valueOf()
    }
 }   
-------------------------------  
function doSomething(){}  
doSomething.prototype.eat = "food" //doSomething函數的原型(prototype)屬性對象添加eat的屬性
var doSomeInstancing  =new doSomething() //創建doSomething函數的實例  通過new關鍵字來調用該函數,它返回這個函數的實例化對象給doSomeInstancing  
doSomeInstancing.prop = "add value";  //給對象doSomeInstancing添加一個“name為prop值為add value”的屬性
console.log(doSomeInstancing);   //輸出這個doSomeIntancing對象 結果現實這個對象有兩個屬性,一個是:prop: "add value" 另一個是:__proto__: Object
console.log(doSomething.prototype); //輸出doSomething.prototype的值是一個對象{eat: "food",constructor: ƒ doSomething(), __proto__: Object
顯然doSomeInstancing.__proto__屬性與doSomething.prototype(構造函數的原型屬性的值是相同)它們的值是相等的。(可以通過===來判斷 __ptototype__為隱式原型)

  • call()、apply()和bind()方法 在前面的函數的間接調用中已經介紹了call()以及apply(),在這裡就不再敘說,就詳細介紹ECMAScript5新增的bind()方法 

bind()方法中的bind翻譯過來就是捆綁、綁定之意,作用就是將函數綁定至某個對象中,倘若一個函數調用了bind()方法並傳入一個對象作為參數,那麼這個方法將返回新的函數。

function f(y){return this.x+y;} //待綁定的函數
var o = {x :1};//將要被綁定的對象
var g = f.bind(o); //將函數f綁定至對象o  相當於var o={x:1, f:function f(y){return this.x+y;}}
console.log(g(2));  //通過g(y)調用o.f(y) 輸出3

bind()方法除了除了第一個實參之外,傳入bind()的實參也會綁定至this.這種應用是一種常見的函數式編程技術,被稱為柯里化(currying)

var sum = function(x,y){return x+y;}  
var succ = sum.bind(null,1);
succ(2)
    • toString()方法
      該方法返回字元串
    • Function()構造函數
    • 高階函數
      • 記憶(memorization)

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

-Advertisement-
Play Games
更多相關文章
  • # apt-get update # apt-get install -y python-software-properties software-properties-common # add-apt-repository ppa:chris-lea/node.js # apt-get updat ...
  • 1.安裝Node封裝模塊 安裝Node封裝模塊很重要,因為開發項目中會用到各種各樣的功能,這時就需要去下載開源的模塊 使用npm install <module_name> module_name為模塊名稱,命令下Node模板到你的開發環境中,並將其放置在node_modules文件夾中, 例如下載 ...
  • (function ($) { $.getUrlParam = function (name) { var reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); var r = window.location.search.substr(1).mat ...
  • 1.Node.js中文官網http://nodejs.cn/download/下載node.js 學習node.js需要有javascript基礎,沒有基礎的可以在http://www.w3school.com.cn/js/index.asp上學習 下載好後,直接安裝。 2.開發工具 我使用的是ec ...
  • 最近做公司新項目用的angular7,中碰到了一個很頭疼的問題在綁定對象中的數據改變時,頁面視圖沒有跟新,需點擊頁面中的時間元素後才會更新。以前使用angularJs也經常碰到類似情況,這種時候一般的方式使使用臟檢查(Dirty checking)讓angularJs檢查綁定到視圖上的數據來實現對頁 ...
  • 這篇隨筆講講HTML5中的表單和表單的一些元素 一、表單的作用是什麼? 概念:表單在網頁中主要是負責對數據信息的採取,表單一共分成三個部分: 1、表單的標簽:這裡麵包含了處理表單的數據所用CGI程式以及數據提交到伺服器的方法。 2、表單域元素:包含著文本框,和密碼框,多行文本框,覆選框,單選框,下拉 ...
  • <!DOCTYPE html> <html> <head> <meta charset="UTF-8"/> <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale= ...
  • 在這一集我們將講到如何從安裝vue-cli開始,到新建一個本地項目,再到vscode中關於eslint的配置,以及本地項目關聯公司遠程項目的基本操作。 一,初始化本地項目 1,首先,全局安裝vue-cli 3.0 2.檢查vue-cli的版本,確定是3.0以上 3,新建一個叫question-edi ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...