第十一天
04-基礎進階-第01天{創建結構、函數進階}
微博發布(案例)
許愿墻(案例)
通過類名獲取元素對象的兼容方法
// 通過類名獲取元素對象的兼容方法
function getElementByClassName(element,className){
if(element.getElementByClassName){// 可以使用這個屬性
return element.getElementByClassName("className");
}else{
// 先找到element里面所有的標簽 然后判斷是否有需要的類名
// 如果有 就把這些標簽放到一個集合中 最后返回這個集合
var elements = element.getElementByTagName("*"); // 通配符找到所有標簽
var filterArr = [];
for(var i = 0;i<elements.length;i++){
if(elements[i].className.indexOf(className)!== -1){
filter.push(elements[i]);
}
}
return filterArr;
}
}
函數進階
預解析
函數的兩種申明
-
函數申明式
function fn(a,b){ return a+b; }
-
函數表達式
var fn = function(a,b){ return a+b; }
預解析概念
- 預解析:js代碼在執行之前有一個過程會對代碼進行預先處理,以便代碼高效準確的執行,這個過程叫做預解析
- 特點:預解析會將變量和函數的申明提升到當前作用域的頂部 然后再開始執行代碼
申明提升
變量提升:預解析會將變量的申明提升到作用域的最前面(只提升申明不提升賦值)
函數提升:預解析會將函數的申明提升到作用域的最前面(函數申明是整個函數體)
-
申明提升時先找var 再找function
console.log(a);// 打印的是函數體 function a(){ console.log(a); } var a = 10; console.log(a); // 分析 1.預解析 解析器會先找var var a;// 此時a為undefined 然后再找function a{};// 此時a變為函數體 2.執行console.log(a);// 此時a的賦值a = 10還沒有執行 所以打印的是函數體 3.執行var a = 10;// 此時給a賦值為10; 4.執行console.log(a);// 此時打印的是10
作用域
變量的兩種類型
var a = 1; // 全局變量
function fn(){
var b = 2; // 局部變量
c = 3;
console.log(a);// 1
console.log(b);// 2
console.log(c);// 3
}
console.log(a);// 1
console.log(b);// undefined
console.log(c);// 3
全局變量:在最外層申明的變量
局部變量:在函數內部申明的變量
隱式全局變量:在函數內部不用關鍵字var申明的變量
塊級作用域&函數作用域
-
塊級作用域:一對花括號{}包裹的區間叫代碼塊,不過JavaScript沒有塊級作用域
console.log(sum);// 因為沒有塊級作用域 所以這里可以訪問到sum,但是變量申明時只提升申明,所以結果是undefined if(false){ var sum = 100; }
-
函數作用域:一個函數代碼塊所包含的區間,叫函數作用域,JavaScript只存在函數作用域
function fn(){ var a = 1; } fn(); console.log(a);// a is not defined 因為存在函數作用域 函數內部申明的變量 函數外包無法訪問 || || \/
作用域鏈
### 1.全局變量 解析器先在函數內部作用域尋找name1的申明,如果找不到,就向上級作用域尋找name1
var name1 = "zs";
function f1(){
name1 = "ls";
}
f1();
console.log(name1);
##分析(偽代碼)
||
||
\/
01.預解析(全局作用域)
var name1;// 變量申明提升
f1{};// 函數申明提升
02.執行
name1 = “zs”;// 變量賦值
03.執行f1(函數作用域)
001.預解析 沒有關鍵字var 也沒有函數申明 所以直接開始執行
002.執行name1 = "ls";// 優先在當前作用域找name1的申明 然后賦值
//但是當前作用域沒有name1的申明 就向上一級尋找到了name1的申明 然后賦值為"ls"
04.執行打印 打印的是全局變量name1 ==> ls
### 2.局部變量 解析器先在函數內部的作用域尋找name2的申明 找了了就使用局部變量
var name2 = "zs";
function f2(){
var name2 = "ls";
}
console.log(name2);
##分析(偽代碼)
||
||
\/
01.預解析(全局作用域)
var name2; //變量申明提升
f2{};// 函數申明提升
02.執行
name2 = "zs";
03.執行f2(函數作用域)
001.預解析
var name2; 變量申明提升
002.執行 現在當前作用域尋找name2 找到了name2的申明 所以給這個局部變量name2賦值"ls"
name2 = "ls";
04.執行打印 打印的是全局變量name2 ==> zs
### 3.作用域鏈 作用域鏈只和在哪里定義有關 和在哪里調用無關
var color = "red";
function outer(){
var anotherColor = "blue";
function inner(){
var tmpColor = color;
color = anotherColor;
anotherColor = tmpColor;
console.log(anotherColor);
}
inner();
}
outer();
console.log(color);
##分析(偽代碼)
||
||
\/
01.預解析(全局作用域)
var color; //變量申明提升
outer{};// 函數申明提升
02.執行
color = "red";
03.執行outer(outer的函數作用域)
001.預解析
var anotherColor;//變量申明提升
inner{};//函數申明提升
002.執行
anotherColor = "blue";
003.執行inner(inner的函數作用域)
0001.預解析
var tmpColor;//變量申明提升
0002.執行
tmpColor = color;// 一直向上找到全局變量color==>"red"
color = anotherColor;// 找到outer中的anotherColor==>"blue"
anotherColor = tmpColor;// 找到outer中的anotherColor 賦值tmpColo的值==>"red"
0003.執行打印
console.log(anotherColor);//找到上級作用域的anotherColor ==> "red"
04.執行打印
console.log(color);// 全局作用域的color ==> "blue"
### 4.作用域鏈 所謂不加var就是全局變量不準確
var name3 = "zs";
function f3(){
var name3 = "ls";
function f4(){
name3 = "ww";
}
f4();
console.log(name3);
}
f3();
console.log(name3);
##分析(偽代碼)
||
||
\/
01.預解析(全局作用域)
var name3; //變量申明提升
f3{};// 函數申明提升
02.執行
name3 = "zs";
03.執行f3(f3的函數作用域)
001.預解析
var name3;//變量申明提升
f4{};// 函數申明提升
002.執行
name3 = "ls";
003.執行f4(f4的函數作用域)
0001.預解析
0002.執行
name3 = "ww";// 先在f4作用域尋找name3 沒找到 然后向上一級到f3作用域尋找name3 找到之后賦值"ww" 也就是f3作用域name3的值被改"ww"
004.執行打印
console.log(name3);// 當前是在f3的作用域 尋找name3 找到了 而且其值為"ww"
04.執行打印(全局作用域)
console.log(name3);// 當前作用域的name3是"zs"
遞歸
階乘
// 求階乘
function getJC(n){
if(n===1){
return;
}
var jc = n*getJC(n-1);
return jc;
}
斐波那契數列
// 斐波那契數列
function getFb(n){
if(n===1||n===2){
return 1;
}
var fb = getFb(n-1) + getFb(n-2);
return fb;
}
構造函數的參數
-
函數也是一種數據類型function
function fn(){ console.log("fn"); } console.log(typeof fn);// function
構造函數Function()
-
構造函數傳一個參數代表的就是函數體function_body
var fn = new Function("alert('a')"); || ||等價 \/ function fn(){ alert("a"); }
-
構造函數如果有多個參數,最后一個代表函數體,其他是形參
var fn = new Function("a","b","c","alert(a+b+c)"); || ||等價 \/ function fn(a,b,c){ alert(a+b+c); }
回調函數
- 被當做參數傳遞的函數叫做回調函數
sort排序
var arr = [8,4,2,1,3,5,6,9,7];
arr.sort(function(a,b){
return a-b;// 升序
//return b-a;// 降序
});
sort內部原理
function sort(arr, fn) {
for (var i = 0; i < arr.length - 1; i++) {
var flag = true;
for (var j = 0; j < arr.length - 1 - i; j++) {
if (fn(arr[j], arr[j + 1]) > 0) {
var temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
flag = false;
}
}
if (flag) {
break;
}
}
return arr;
}
function fn(a,b){
return a-b;
}
sort([9,8,7,6,5,4,3,2,1],fn);// fn即回調函數