JS中函數的本質,定義、調用,以及函數的參數和返回值

来源:https://www.cnblogs.com/chenyingying0/archive/2020/02/12/12297122.html
-Advertisement-
Play Games

要用面向對象的方式去編程,而不要用面向過程的方式去編程 對象是各種類型的數據的集合,可以是數字、字元串、數組、函數、對象…… 對象中的內容以鍵值對方式進行存儲 對象要賦值給一個變數 var cat={ "name":"喵1", "age":4, "family":["喵爸","喵媽"], "spea ...


要用面向對象的方式去編程,而不要用面向過程的方式去編程


 

對象是各種類型的數據的集合,可以是數字、字元串、數組、函數、對象……

對象中的內容以鍵值對方式進行存儲

對象要賦值給一個變數

    var cat={
        "name":"喵1",
        "age":4,
        "family":["喵爸","喵媽"],
        "speak":function(){
            console.log("喵喵~");
        },
        "friend":{
            "name":"喵2",
            "age":5
        }
    }

上面是對象的字面量的創建方式,簡單直接

除此之外,還有對象的構造函數的創建方式

    var cat=new Object();

還有JavaScript5新增的一種方式

該方式在老版本的瀏覽器中存在相容性問題

    Object.create();

獲取、設置、添加、修改對象的值:

對象.屬性名=屬性值

對象[ 屬性名 ]=屬性值

    var cat={
        "name":"喵1",
        "age":4,
        "family":["喵爸","喵媽"],
        "speak":function(){
            console.log("喵喵~");
        },
        "friend":{
            "name":"喵2",
            "age":5
        }
    }

    cat.name="喵喵1";
    cat.age=6;
    cat.type="英短";
    console.log(cat.name);//喵喵1
    console.log(cat["age"]);//6
    console.log(cat.type);//英短

刪除對象的屬性:

delete 對象.屬性

    var cat={
        "name":"喵1",
        "age":4,
        "family":["喵爸","喵媽"],
        "speak":function(){
            console.log("喵喵~");
        },
        "friend":{
            "name":"喵2",
            "age":5
        }
    }

    cat.type="英短";
    console.log(cat.type);//英短

    delete cat.type;
    console.log(cat.type);//undefined

檢測對象是否擁有某個屬性:

屬性名 in 對象

    var cat={
        "name":"喵1",
        "age":4,
        "family":["喵爸","喵媽"],
        "speak":function(){
            console.log("喵喵~");
        },
        "friend":{
            "name":"喵2",
            "age":5
        }
    }

    console.log("name" in cat);//true
    console.log("type" in cat);//false

對象的枚舉,遍歷對象中的各個屬性

    var cat={
        "name":"喵1",
        "age":4,
        "family":["喵爸","喵媽"],
        "speak":function(){
            console.log("喵喵~");
        },
        "friend":{
            "name":"喵2",
            "age":5
        }
    }

    for(var p in cat){
        console.log(p);
        //name age family speak friend
    }
    var cat={
        "name":"喵1",
        "age":4,
        "family":["喵爸","喵媽"],
        "speak":function(){
            console.log("喵喵~");
        },
        "friend":{
            "name":"喵2",
            "age":5
        }
    }

    for(var p in cat){
        console.log(p+": "+cat[p]);

        console.log(p);//獲取屬性名
        //console.log(cat.p);// 寫法錯誤
        console.log(cat[p]);//獲取屬性值 寫法正確

        console.log(cat["n"+"ame"]);//喵1  []中可以添加字元串的拼接等操作
    }

匿名函數,如:

window.onload=function(){

}

函數一次執行完畢之後,會將局部作用域和局部變數銷毀,因此外部無法調用到

但函數本身並沒有被銷毀,可以進行多次調用執行


 

為什麼要使用函數:

代碼復用(自己的代碼和別人的代碼,如jquery)

統一修改和維護

增加程式的可讀性


 

函數的本質:對象

定義方式:字面量定義、構造函數定義

//字面量定義
function add(n1,n2){

}
//構造函數定義
new Function("n1","n2","....");

函數和對象一樣,可以添加屬性和方法

function person(){
    console.log("cyy");
}
//添加屬性
person.age=25;
//添加方法
person.speak=function(words){
    console.log(words);
}
console.log(person.age);//25
person.speak("hh~");//hh~
person();//cyy

函數可以作為數據值使用:

作為數據值保存在一個變數中

var fn=function(){
    return "這是一個函數";
}
console.log(fn());//這是一個函數
console.log(fn);
/*
ƒ (){
    return "這是一個函數";
}
*/

此時fn列印出來的就是函數本體

函數也可以作為參數來使用:

function fn(){
    alert(1);
}
setTimeout(fn,1000);//此處需要傳函數本體
//此處不能加括弧,如果加了括弧,會立刻調用,而不是等到1秒之後

函數可以作為返回值使用:

function fn(){
    return function(){
        console.log("fn中的fn");
    }
}
//調用
var newFn=fn();
newFn();//fn中的fn

// 或者

fn()();//fn中的fn

函數的三種定義方式

// 字面量方式

    // function 聲明
    function add(){

    }

    // var 賦值表達式
    var add=function(){

    };

//構造函數
    var add=new Function("num1","num2","return num1+num2");
    add();

區別:

字面量方式比構造函數方式簡潔

最重要的是預解析的區別

funtion聲明的函數,可以先調用,再創建

函數預解析的時候會提前定義

    add();
    function add(){
        return 1;
    }

用var賦值表達式創建的函數,如果先調用,再創建,會報錯

因為var在預解析時賦值為undefined

    add();
    var add=function(){
        return 1;
    };

function聲明和var賦值表達式聲明,這兩種都是很好的選擇

構造函數過於複雜,不推薦使用


 

函數定義的位置

全局作用域下的函數,在哪裡都能調用

add();
function add(){
    add();
}
add();

function fn(){
    add();
}

局部作用域下的函數

    //fn();  無法調用
    function add(){
        fn();
        function fn(){
            fn();
            function fn3(){
                fn();
            }
        }
        function fn2(){
            fn();
        }
    }
    //fn();  無法調用

裡層可以訪問外層的函數,外層不能訪問裡層的函數

代碼塊中定義的函數:

由於js中沒有塊級作用域,所以依然是處於全局作用域中

都會出現預解析中函數被提前聲明

if(true){
    function fn1(){

    }
}else{
    function fn2(){
        
    }
}

改成下麵這樣就可以實現按照條件進行聲明,也是因為預解析的機制

if(true){
    var fn1=function (){

    }
}else{
    var fn2=function fn2(){

    }
}

對象中的函數

使用對象.函數名進行調用

var person={
    name:"cyy",
    setAge:function(age){
        this.age=age;//this指向當前對象
    }
}
person.setSex=function(sex){
    this.sex=sex;
}
person.setAge(25);
person.setSex("girl");
console.log(person.age);//25
console.log(person.sex);//girl

普通函數的調用:

命名函數的調用

function add(){

}
add();

匿名函數的調用:

如果直接在匿名函數後面加上括弧進行調用,會報錯

function(){
    alert(1);
}();//Uncaught SyntaxError: Unexpected token (

解決方法是,將這段匿名函數執行的代碼,賦值給一個變數

var fn=function(){
    alert(1);
}();//1

第二種解決方法:

將函數用括弧括起來,實現匿名函數自執行

(function(){
    alert(1);
})();//1

括弧把整體括起來也能實現一樣的效果

(function(){
    alert(1);
}());//1

或者在function前加上合法的字元也可以,如!+-~

!function(){
    alert(1);
}();//1

或者放在console.log裡面

console.log(function(){
    alert(1);
}());

以上這些方式的共同目的,就是不讓匿名函數的function在開頭位置出現


 

遞歸調用:

自己調用自己

實現階乘

function fn(num){
    if(num<=1) return 1;
    return num*fn(num-1);
}
console.log(fn(5));
/*
return 5*fn(4)
return 5*4*fn(3)
return 5*4*3*fn(2)
return 5*4*3*2*fn(1)
return 5*4*3*2*1
*/

匿名函數也是函數,當它自執行的時候,會創建自己的函數內部作用域,在執行完畢之後會被銷毀,因此在外部無法訪問到自執行的匿名函數內部

//此處創建函數內部作用域
(function add(n1,n2){
    return n1+n2;
})();
console.log(add(3,4));//在全局無法訪問到函數內部的函數add

方法的調用:

對象中的方法,使用對象.方法名進行調用

var operation={
    add:function(n1,n2){
        return n1+n2;
    },
    sub:function(n1,n2){
        return n1-n2;
    }
}
console.log(operation.add(3,4));//7

以下這種也是方法,是點擊瀏覽器時瀏覽器自動幫我們完成調用;

也可以使用方法調用的方式來進行調用

    document.onclick=function(){
        alert(1);
    }
    document.onclick();//等同於點擊屏幕的效果

關於對象中的屬性,什麼時候加引號,什麼時候不加引號

對於合法的標識符,加不加引號都可以;

不合法的標識符,必須加引號,否則會引起報錯

var operation={
    add:function(n1,n2){
        return n1+n2;
    },//合法的屬性名可以不加引號
    sub:function(n1,n2){
        return n1-n2;
    },
    "@":function(){

    }//不合法的屬性名,會引起報錯,必須加引號
}

合法的標識符,調用時使用對象.方法名即可

非法的標識符,調用時使用對象[ " 方法名 " ]

var operation={
    add:function(n1,n2){
        return n1+n2;
    },//合法的屬性名可以不加引號
    sub:function(n1,n2){
        return n1-n2;
    },
    "@":function(word){
        alert(word);
    }//不合法的屬性名,會引起報錯,必須加引號
}
console.log(operation.add(2,5));//7
console.log(operation["@"]("hh~"));//hh~

[ ] 加引號和不加引號的區別

var operation={
    add:function(n1,n2){
        return n1+n2;
    },//合法的屬性名可以不加引號
    sub:function(n1,n2){
        return n1-n2;
    },
    "@":function(word){
        return word;
    },//不合法的屬性名,會引起報錯,必須加引號
    key:function(n1,n2){
        return "key~";
    }
}
var key="add";
console.log(operation.key(2,3));//key~
console.log(operation["key"](2,3));//key~
console.log(operation[key](2,3));//5

方法的鏈式調用

如jquery

$("p").html("html").css("color","red")....

對象中要使用鏈式調用,則方法中需要返回當前對象

var operation={
    add:function(n1,n2){
        console.log(n1+n2);
        return this;
    },
    sub:function(n1,n2){
        console.log(n1-n2);
        return this;
    }
}
operation.add(5,3).sub(4,2);
//要保證operation.add(5,3)能夠返回operation對象
//就需要添加return this

 構造函數的調用:

構造函數命名時一般首字母大寫

調用時用new+函數名,返回值是一個對象

function Person(){

}
var obj=new Person();

js中內置的構造函數,常見的有:

Object()
new Object()

Array()
new Array()

通過new關鍵字來調用

用構造函數的方式定義對象和數組,並添加內容

var person=new Object();
person.name="cyy";

var arr=new Array();
arr[0]=1;

函數的間接調用

.call   第一個參數是改變this的指向,後面傳遞參數的方式就是一個一個傳

.apply   第一個參數是改變this的指向,後面傳遞參數的方式是通過數組來傳遞(或者類數組)

var name="cyy";
var person={};
person.name="cyy2";
person.getName=function(){
    return this.name;//此處的this指向person對象
}
console.log(person.getName());//直接調用  cyy2

console.log(person.getName.call(window));//間接調用,此時this被指向了window,返回的是window.name  cyy
console.log(person.getName.apply(window));//間接調用  cyy
function add(n1,n2){
    return n1+n2;
}
console.log(add(1,2));//直接調用 3
console.log(add.call(window,1,2));//間接調用 3
console.log(add.apply(window,[1,2]));//間接調用 3
function add(n1,n2){
    return n1+n2;
}
var arr=[4,6];
console.log(add.apply(window,arr));//10

只有函數擁有call和apply方法,兩者唯一的區別在於它們的傳參方式


 

函數的參數

參數傳遞的本質是將實參賦值給形參

參數的個數

1、形參個數=實參個數

function add(n1,n2){
    return n1+n2;
}
console.log(add(3,5));

2、實參個數 < 形參個數

多用於有可選參數的情況

function pow(base,pow=2){
    return Math.pow(base, pow);
}
console.log(pow(3));//9
console.log(pow(3,3));//27

3、實參個數 > 形參個數

如果無法得知有多少個實參,可以使用arguments

arguments是一個類數組,用於保存實參的信息

通過arguments[index] 獲取某一個參數

arguments.length 實參的個數

function add(){
    if(arguments.length==0) return;
    var sum=0;
    for(var i=0,len=arguments.length;i<len;i++){
        sum+=arguments[i];
    }
    return sum;
}
console.log(add());//undefined
console.log(add(1,2,3,4,5));//15

arguments 是類數組,實質上還是對象

索引是數組下標,數字開頭的變數名不合法,因此需要加引號

{
    '0': 1,
    '1': 2,
    '3': 4,
    length: 3
}

可以通過arguments來修改參數的值

function speak(m){
    arguments[0]="";
    return m;
}
console.log(speak("hh"));//

arguments是每個函數中獨有的,不會跨函數

function fn1(){
    console.log(arguments);//Arguments [1, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    function fn2(){
        console.log(arguments);//Arguments [2, callee: ƒ, Symbol(Symbol.iterator): ƒ]
    }
    fn2(2);
}
fn1(1);

arguments.callee  指代函數本身

function add(){
    console.log(arguments.callee);
}
add();

arguments.callee 常用於遞歸中

function factorial(num){
    if(num==1) return 1;
    return num*factorial(num-1);
}
console.log(factorial(5));//120


function factorial(num){
    if(num==1) return 1;
    return num*arguments.callee(num-1);
}
console.log(factorial(5));//120

不過在嚴格模式下,不允許使用arguments.callee(也不允許不使用var聲明變數)

此時的解決方法就是將函數賦值給一個變數,這樣函數本身的名字不會影響調用

"use strict";

var myfn=function factorial(num){
    if(num==1) return 1;
    return num*factorial(num-1);
}
console.log(myfn(5));//120

實參的個數 arguments.length

形參的個數 函數名.length 或者arguments.callee.length

function add(n1,n2){
    if(arguments.length != add.length) throw new Error("請傳入"+add.length+"個參數!");
}
console.log(add(5));//Uncaught Error: 請傳入2個參數!

什麼做參數

1、沒有參數

2、數字做參數

3、字元串( 如選擇DOM節點,$("p") )

4、布爾值(保持函數的純潔性,建議一個函數只做一件事情)

5、undefined(可選參數必須放在最後)

6、null

7、數組 

$.each(["a","b","c"],function(index,item)){
    console.log(index);//0 1 2
    console.log(item);//a b c
}

8、對象

$.each({name:"cyy",age:24},function(index,item)){
    console.log(index);//name age
    console.log(item);//cyy 24
}

使用對象作為參數的好處(可以自由調換順序)

function fn(obj){
    var person={};
    person.name=obj.name||"cyy";
    person.age=obj.age||24;
    person.tel=obj.tel||110,
    person.addr=obj.addr||"China";
    return person;
}
var cyy={
    name: "cyy1",
    age:25
}
console.log(fn(cyy));//{name: "cyy1", age: 25, tel: 110, addr: "China"}

9、函數

回調函數,如 setTimeout(fn, time);


 

函數的返回值

return:

表示函數結束

將值返回

什麼可以做返回值:

直接return ,返回值是undefined

數字

字元串 :alert() 輸出的都是字元串,會預設調用.toString() 方法

布爾值:常用於表單驗證

null 和 undefined

數組

function add(n1,n2){
    return [n1,n2,n1+n2];
}
console.log(add(5,6));//(3) [5, 6, 11]

對象

function fn(){
    return {
        name:"cyy",
        age:25
    }
}

註意return後面不要換行,否則預設是分號,到此結束;於是後面的會報錯

function fn(){
    //return會預設後面是分號,結束
    return 
    {
        name:"cyy",
        age:25
    }
}

函數

需要用()()來調用


 

document.write() 執行時會調用.toString() 方法,嘗試將結果轉換為字元串形式

document.write([1,2,3]);//1,2,3
document.write({
    name:"cyy"
});//[object Object]
document.write({
    name:"cyy",
    toString:function(){
        return "hh~";
    }
});//hh~
function count(){
    var num=1;
    return function(){
        return num++;
    }
}
//每次調用count()時,num都會被初始化
//並且return num++ 是先返回num,再執行++
console.log(count()());//1
console.log(count()());//1
console.log(count()());//1
//count()只執行了一次,因此num只初始化一次
//後面能夠每次都進行遞增+1
var fn=count();
console.log(fn());//1
console.log(fn());//2
console.log(fn());//3

 


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

-Advertisement-
Play Games
更多相關文章
  • 如果介紹HTML網頁基本標簽的嵌套規則,首先要說的就是元素的分類。元素可以劃分為塊級元素和行級元素,塊級元素是什麼?它可以獨占一行,可以設置寬高度,預設是100%;行級元素與之相反,它的內容決定它的寬高度,至於特殊字元就當成是文字來看!嵌套規則總結如下幾點:1.塊元素可以嵌套行元素2.行元素可以嵌套... ...
  • 什麼是網頁的佈局?網頁佈局就是我們在拿到設計稿後進行切片處理(所謂切圖),然後我們通過DIV+CSS佈局,書寫靜態頁面按照設計稿還原排列,把我們想要實現的功能與內容進行填充!早期的frameset佈局主要書寫管理後臺控制菜單的切換實現局部的刷新,至於頁面的嵌套則是通過iframe ...
  • Electron 和 Vue 都是幹啥的,就不做過多介紹了,可以去官網瞅瞅。下麵總結 Electron+Vue 創建項目,Electron + Vue 創建項目實際上相當於:創建Vue項目 + Electron封裝。 一、創建Vue項目 + Electron封裝 1、創建Vue項目 通過 Vue腳手 ...
  • <script language=javascript> window.onload=function(){ //刷新父頁面 window.opener.location.reload(); } </script> 相關連接 JS 彈出小視窗 ...
  • 面向對象: 對代碼的一種抽象,對外統一提供調用介面的編程思想 對象的屬性:事物自身擁有的東西 對象的方法:事物的功能 對象:事物的一個實例 對象的原型:.prototype -> 記憶體地址 -> 存儲了一個對象 function fn(){ return 1; } alert(fn.prototyp ...
  • 用JS實現簡易計算器 首先創建結構和樣式 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1 ...
  • 1. Ajax是什麼? 全稱是 asynchronous javascript and xml,是已有技術的組合,主要用來實現客戶端與伺服器端的非同步通信效果(無需重新載入整個網頁的情況下),實現頁面的局部刷新。 通過在後臺與伺服器進行少量數據交換,AJAX 可以使網頁實現非同步更新,用於創建快速動態網 ...
  • 表單是什麼?表單是前端和伺服器做交互的一種機制,表單收集用戶輸入信息,之後發送或者提交給伺服器。用戶在輸入的信息稱之為內容,內容的文本分為普通和密碼型,用戶通過單選框、覆選框、下拉框(也就是下拉菜單)完成內容信息輸入,最後通過提交按鈕發送給伺服器!這裡要講到瀏覽器怎麼發送給伺服器?涉及到http協議... ...
一周排行
    -Advertisement-
    Play Games
  • Dapr Outbox 是1.12中的功能。 本文只介紹Dapr Outbox 執行流程,Dapr Outbox基本用法請閱讀官方文檔 。本文中appID=order-processor,topic=orders 本文前提知識:熟悉Dapr狀態管理、Dapr發佈訂閱和Outbox 模式。 Outbo ...
  • 引言 在前幾章我們深度講解了單元測試和集成測試的基礎知識,這一章我們來講解一下代碼覆蓋率,代碼覆蓋率是單元測試運行的度量值,覆蓋率通常以百分比表示,用於衡量代碼被測試覆蓋的程度,幫助開發人員評估測試用例的質量和代碼的健壯性。常見的覆蓋率包括語句覆蓋率(Line Coverage)、分支覆蓋率(Bra ...
  • 前言 本文介紹瞭如何使用S7.NET庫實現對西門子PLC DB塊數據的讀寫,記錄了使用電腦模擬,模擬PLC,自至完成測試的詳細流程,並重點介紹了在這個過程中的易錯點,供參考。 用到的軟體: 1.Windows環境下鏈路層網路訪問的行業標準工具(WinPcap_4_1_3.exe)下載鏈接:http ...
  • 從依賴倒置原則(Dependency Inversion Principle, DIP)到控制反轉(Inversion of Control, IoC)再到依賴註入(Dependency Injection, DI)的演進過程,我們可以理解為一種逐步抽象和解耦的設計思想。這種思想在C#等面向對象的編 ...
  • 關於Python中的私有屬性和私有方法 Python對於類的成員沒有嚴格的訪問控制限制,這與其他面相對對象語言有區別。關於私有屬性和私有方法,有如下要點: 1、通常我們約定,兩個下劃線開頭的屬性是私有的(private)。其他為公共的(public); 2、類內部可以訪問私有屬性(方法); 3、類外 ...
  • C++ 訪問說明符 訪問說明符是 C++ 中控制類成員(屬性和方法)可訪問性的關鍵字。它們用於封裝類數據並保護其免受意外修改或濫用。 三種訪問說明符: public:允許從類外部的任何地方訪問成員。 private:僅允許在類內部訪問成員。 protected:允許在類內部及其派生類中訪問成員。 示 ...
  • 寫這個隨筆說一下C++的static_cast和dynamic_cast用在子類與父類的指針轉換時的一些事宜。首先,【static_cast,dynamic_cast】【父類指針,子類指針】,兩兩一組,共有4種組合:用 static_cast 父類轉子類、用 static_cast 子類轉父類、使用 ...
  • /******************************************************************************************************** * * * 設計雙向鏈表的介面 * * * * Copyright (c) 2023-2 ...
  • 相信接觸過spring做開發的小伙伴們一定使用過@ComponentScan註解 @ComponentScan("com.wangm.lifecycle") public class AppConfig { } @ComponentScan指定basePackage,將包下的類按照一定規則註冊成Be ...
  • 操作系統 :CentOS 7.6_x64 opensips版本: 2.4.9 python版本:2.7.5 python作為腳本語言,使用起來很方便,查了下opensips的文檔,支持使用python腳本寫邏輯代碼。今天整理下CentOS7環境下opensips2.4.9的python模塊筆記及使用 ...