23 函式的引數及問題、作用域、預解析(變數提升)、函式返回值、獲取非行間樣式、函式封裝
函式的引數
-
形參: 形式引數 接收實參傳遞過來的資料 function後面的()
-
實參: 具體的資料 傳遞給形參的資料 呼叫的()
-
arguments: 實參的集合 每個函式都有 當形參和實參的個數不確定的時候
-
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);
函式的問題
-
函式名重複的時候 後面的覆蓋前面
function b(){
console.log(1);
}
getType(b);
// 問題: 1. 函式名重複的時候 後面的覆蓋前面
function b(){
console.log(333);
}
console.log(b); -
函式的引數個數不對應的時候
形參個數多於實參個數, 多餘的形參會被賦值成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);
作用域
作用域: 對變數或函式起作用的區域
對某一個變數或者函式有訪問許可權的區域
域:區域 範圍
作用:讀(獲取) 寫(設定)
作用域的分類
-
全域性作用域: 函式外的區域 script標籤下的區域
-
區域性作用域: 函式內的區域 function(){ 區域性作用域 }
也叫做: 函式作用域
// 全域性
var a = 20;
function sum(){
// 區域性
console.log(1);
console.log(a);
}
變數和函式分類
根據函式和變數宣告位置的不同,分為全域性變數、全域性函式、區域性變數、區域性函式
-
全域性作用域中, 用var宣告的變數 就是全域性變數 可以在頁面的任何位置被讀寫
用function宣告的函式 就是全域性函式 可以在頁面的任何位置被讀寫
-
區域性作用域中, 用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
預解析(變數提升)
-
找 找var和function 將var宣告的變數 宣告提到最前, 變數值是undefined, 將function宣告的函式整個提到最前,儲存在記憶體中
-
從上往下逐行解析
變數賦值在從上到下逐行解析過程中 遇到 賦值運算子 = += -= *= /= %= 會進行賦值 遇到其他運算子正常計算; 函式在遇到呼叫程式碼的時候,會形成新的區域性作用域來執行程式碼
例子一
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 }
函式封裝
-
建立一個空函式
-
重複程式碼放入
-
原位置上呼叫 解決報錯
-
抽參 分析可變的資料 抽取成引數 從上到下 逐行分析
-
傳參呼叫 誰抽取出來 就把誰傳進去
-
設定返回值
-
接收返回值 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; }