1. 程式人生 > 實用技巧 >23 函式的引數及問題、作用域、預解析(變數提升)、函式返回值、獲取非行間樣式、函式封裝

23 函式的引數及問題、作用域、預解析(變數提升)、函式返回值、獲取非行間樣式、函式封裝

23 函式的引數及問題、作用域、預解析(變數提升)、函式返回值、獲取非行間樣式、函式封裝

函式

函式的引數

  1. 形參: 形式引數 接收實參傳遞過來的資料 function後面的()

  2. 實參: 具體的資料 傳遞給形參的資料 呼叫的()

  3. arguments: 實參的集合 每個函式都有 當形參和實參的個數不確定的時候

  4. 所有的資料型別都可以作為函式的引數 但是一般不用null和undefined 易於出錯

    number string boolean null undefined object array function

    function getType(a){
    console.log(a);
    console.log(typeof a);
    }
    getType('123');
    getType(true);
    getType(null);
    getType(undefined);
    getType({name: '張三'});
    getType([1,2,3,4]);
    function b(){
    console.log(1);
    }
    getType(b);

函式的問題

  1. 函式名重複的時候 後面的覆蓋前面

    function b(){
    console.log(1);
    }
    getType(b);

    // 問題: 1. 函式名重複的時候 後面的覆蓋前面
    function b(){
    console.log(333);
    }
    console.log(b);
  2. 函式的引數個數不對應的時候

    形參個數多於實參個數, 多餘的形參會被賦值成undefined

    實參個數多於形參個數, 多餘的實參就不能通過形參獲取, 但是可以通過arguments獲取

    function fn1(a, b, c){
    console.log(a, b, c);
    console.log(arguments);
    }
    // fn1(1, 2, 3); // a = 1 b = 2 c = 3
    fn1(1, 2);
    fn1(1,2,3,4);

作用域

作用域: 對變數或函式起作用的區域

對某一個變數或者函式有訪問許可權的區域

域:區域 範圍

作用:讀(獲取) 寫(設定)

作用域的分類

  1. 全域性作用域: 函式外的區域 script標籤下的區域

  2. 區域性作用域: 函式內的區域 function(){ 區域性作用域 }

也叫做: 函式作用域

// 全域性
var a = 20;
function sum(){
// 區域性
console.log(1);
console.log(a);
}

變數和函式分類

根據函式和變數宣告位置的不同,分為全域性變數、全域性函式、區域性變數、區域性函式

  1. 全域性作用域中, 用var宣告的變數 就是全域性變數 可以在頁面的任何位置被讀寫

    用function宣告的函式 就是全域性函式 可以在頁面的任何位置被讀寫

  2. 區域性作用域中, 用var宣告的變數 就是區域性變數 只能在宣告的函式內部進行使用 出了{}就會被銷燬

    用function宣告的函式 就是區域性函式 只能在宣告的函式內部進行使用 出了{}就會被銷燬

// 全域性
var a = 20;
function sum(){
// 區域性
console.log(1);
console.log(a);
}

console.log(a); // 20
sum(); // 20

function fn(){
var b = 30;
console.log(b);

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

fn1();
}
fn(); // 30
// console.log(b); // 報錯
// fn1(); 報錯

作用域鏈

作用域鏈: js中的一種查詢方式, 決定了變數和函式向上查詢的方式

// var a = 20;

// function sum(){
// console.log(a);
// }

// sum();



// var a = 30;
// function sum(){
// var a = 40;
// console.log(a);
// }
// sum(); // 40


var a = 30;
function sum(){
a = 40;
console.log(a);
}
sum(); // 40

預解析(變數提升)

  1. 找 找var和function 將var宣告的變數 宣告提到最前, 變數值是undefined, 將function宣告的函式整個提到最前,儲存在記憶體中

  2. 從上往下逐行解析

變數賦值在從上到下逐行解析過程中 遇到 賦值運算子 = += -= *= /= %= 會進行賦值 遇到其他運算子正常計算; 函式在遇到呼叫程式碼的時候,會形成新的區域性作用域來執行程式碼

例子一

console.log(a);
var a = 20;
function sum(){
console.log(a);
}
sum();

/*
---------------解析過程---------------
var a;
function sum(){
console.log(a);
}
console.log(a); undefined
a = 20;
sum(); 20
*/

例子二

// 變數名 和 函式名重複的時候  後面的覆蓋前面的
console.log(a);
var a = 3;
console.log(typeof a);
function a() {
alert('1');
}
// a();
var a = 4;
console.log(a);
// a();
function a() {
alert(5);
};
// a();
console.log(a);

// -------解析步驟--------
/* var a; // 13
var a; // 19
function a() { // 15
alert('1');
}
function a() { // 22
alert(5);
};
console.log(a); // 12 22行的函式
a = 3; // 13
console.log(typeof a); // 14 number typeof 3 ---> number
a(); // 18 報錯 a = 3 不是函式
a = 4; // 19
console.log(a); // 20 4
a(); // 21 報錯
a(); // 25 報錯
console.log(a); // 26 4 */

例子三

// 用變數宣告函式的時候  函式有沒有名字  都不提前  用了 字面量宣告函式這種方式,只會將函式名提到最前
console.log(a);
console.log(d);
var a = 3;

var d = function a() {
    alert('1');
};
console.log(a);
console.log(d);
a();

// ----解析過程----
// var a; // 15
// var d; // 17
// console.log(a); // 13  undefined
// console.log(d); // 14  undefined
// a = 3; // 15
// d = function () { // 17行
//     alert('1');
// };
// console.log(a); // 20  3
// console.log(d); // 21 function
// a(); // 22   報錯

例子四

/* 
    當遇到函式呼叫的時候,新的區域性作用域來執行程式碼, 由於在新的區域性作用域中 相當於上下文的執行環境進行了改變  函式中的程式碼要按照解析順序重新執行
*/
function fn(a) { // 形參  類似於變數  a === var a
    console.log(a);
    var a = 3;
    console.log(a);
}

fn(2);

// ----解析步驟-----
// function fn(a) { // 形參  類似於變數  a === var a;  var a; 
//     // 什麼時候傳參  呼叫的時候傳參  形參賦值  在 var a後面賦值
//     a = 2;
//     console.log(a); // undefined  2
//     a = 3;
//     console.log(a); // 3
// }
// fn(2);

例子五

var a = 4;
function fn(b) {
    console.log(a);   
    var a = 3;
    console.log(a);
};

fn();
console.log(a);

// ------解析步驟------
// var a; // 12
// function fn(b) { // 13   b === var b
//     // console.log(a);   
//     // var a = 3;
//     // console.log(a);
//     // ----解析步驟----
//     var a; // 15
//     console.log(a); // 14
//     a = 3; // 15
//     console.log(a); // 16
// };
// a = 4; // 12
// fn(); // 14---undefined  16---3  a--區域性a
// console.log(a); //  全域性a  4

例子六

var a = 4;
function fn(a) {
    console.log(a);
    a = 5;

};

fn(a);
console.log(a);

// ----解析過程-----  傳參  變數名一樣
// var a; // 14
// function fn(a) { // 15  a === var a   a---區域性a   a = 4
//     console.log(a); // 區域性a = 4
//     a = 5; // 區域性a  a = 5
// };
// a = 4; // 14  全域性a
// fn(a); // 21 實參a---全域性a---a=4   fn(4);
// console.log(a); // 22  全域性a  4

例子七

function fn(a) {
    var s = a;
    s.name = '優就業';
};

var json = {
    name: '小u'
};

fn(json);
console.log(json);

// 解析過程  物件---儲存問題---記憶體中:宣告在棧  儲存在堆   16進位制地址
// var json;
// function fn(a) { // var a;  a = json的地址
//     // var s = a;
//     // s.name = '優就業';
//     // -------
//     var s;
//     s = a;
//     s.name = '優就業';
// };
// json = {
//     name: '小u'
// };
// fn(json); // fn(16進位制地址)
// console.log(json); // 通過16進位制地址訪問資料 {name: '優就業'}

函式返回值

每個函式執行結束以後都會有一個返回值

在呼叫的時候接收: var 變數 = 函式名();

沒有設定返回值的時候,預設返回undefined

設定返回值:

return 值;

函式遇到return, 直接結束, 後續程式碼不在執行

使用場景:

當函式內的資料 要在函式外使用的時候 要在函式外獲取的時候 將這個資料作為返回值返回出去

function a(){
    console.log(1);
}
var res = a();
console.log(res);

function b(){
    return 30;
}
var res1 = b();
console.log(res1);

function c(){
    console.log(1);
    return 20;
    console.log(2);
    console.log('好開心呀');
}
var res2 = c();
console.log(res2);

當返回多個數據的時候:陣列、物件

陣列: 返回的資料必須按照規定好的順序返回,如果有一個錯,有可能所有的都錯

物件: 返回的資料通過屬性名直接獲取,不受其它資料影響, 程式碼比較冗餘

建議是用物件作為返回值

function sum(){
    var s = 0;
    for(var i = 0; i <= 100; i++){
        s += i;
    }
    console.log(s);

    // json格式  屬性名:屬性值
    var obj = {
        m: 0,
        s: s,
        i: i
    };
    return obj;


    // return [0, s, i];
    // return [s, i];

    // return s;
    // return i;

    // return s,i;
    // return s;
}
var a = sum();
console.log(a);
// console.log(s); // s是區域性變數  報錯

// console.log('總和是:', a[0]);
console.log('總和是:', a.s);

返回值型別

返回值的資料型別:

number string boolean null undefined array object function

一般不設定null和undefined

function getReturn(){
    // return 50;
    // return '1234';
    // return true;
    // return null;
    // return undefined;
    // return [23, 45];
    // return {
    //     s: 5050,
    //     i: 101
    // };
    function fn(){
        console.log(1);
    }
    return fn;

}
var a = getReturn();
console.log(a);
console.log(typeof a);

// 如果a是true  彈出1
// if(a){
//     alert(1);
// }

if(typeof a == 'function'){
    // 呼叫函式
    a();
}

// fn(); // 區域性函式 在全域性中不能直接用

獲取非行間樣式

標準(ie9以上): getComputed(元素).屬性名

ie678: 元素.currentStyle.屬性名

// 標準
// console.log(getComputedStyle(div));
// console.log(getComputedStyle(div).width); // 200px

// console.log(getComputedStyle); // ie678 “getComputedStyle”未定義  變數未宣告

// ie678
// console.log(div.currentStyle); // 標準: undefined  ie678: 物件
// console.log(div.currentStyle.width); // 200px

// 判斷當前是什麼瀏覽器
// 如果currentStyle不是undefined  不為假  就是ie678
if(div.currentStyle){
    // ie678
    console.log(div.currentStyle.width); // 200px
} else {
    // 標準
    console.log(getComputedStyle(div).width); // 200px
}

var p = document.getElementsByTagName('p')[0];
if(p.currentStyle){
    // ie678
    console.log(p.currentStyle.width); // 200px
} else {
    // 標準
    console.log(getComputedStyle(p).width); // 200px
}

函式封裝

  1. 建立一個空函式

  2. 重複程式碼放入

  3. 原位置上呼叫 解決報錯

  4. 抽參 分析可變的資料 抽取成引數 從上到下 逐行分析

  5. 傳參呼叫 誰抽取出來 就把誰傳進去

  6. 設定返回值

  7. 接收返回值 var 變數 = 函式();

var p = document.getElementsByTagName('p')[0];
// 元素.屬性名  元素['屬性名']
var wid = getStyle(p, 'width');
var hei = getStyle(p, 'height');

// 判斷當前p的寬度如果是200 變成300 
// console.log(w); // 區域性變數  要想在全域性中拿到 需要用return設定返回值
console.log(wid, hei);

if(wid == '200px'){
    alert(1);
}

// attr--形參 類似變數
function getStyle(ele, attr) {
    // ele: 元素
    // attr: 屬性名  
    var w = 0;
    if (ele.currentStyle) {
        // ie678
        // console.log(ele.currentStyle[attr]);
        w = ele.currentStyle[attr];
    } else {
        // 標準
        // console.log(getComputedStyle(ele)[attr]); // 200px
        w = getComputedStyle(ele)[attr];
    }
    return w;
}