第十一天
04-基础进阶-第01天{创建结构、函数进阶}
- 第十一天
- 微博发布(案例)
- 许愿墙(案例)
- 通过类名获取元素对象的兼容方法
- 函数进阶
- 预解析
- 函数的两种申明
- 预解析概念
- 申明提升
- 作用域
- 变量的两种类型
- 块级作用域&函数作用域
- 作用域链
- 预解析
- 递归
- 阶乘
- 斐波那契数列
- 构造函数的参数
- 构造函数Function()
- 回调函数
- sort排序
- sort内部原理
微博发布(案例)
许愿墙(案例)
通过类名获取元素对象的兼容方法
// 通过类名获取元素对象的兼容方法
function getElementByClassName(element,className){
if(element.getElementByClassName){// 可以使用这个属性
return element.getElementByClassName("className");
}else{
// 先找到element里面所有的标签 然后判断是否有需要的类名
// 如果有 就把这些标签放到一个集合中 最后返回这个集合
var elements = element.getElementByTagName("*"); // 通配符找到所有标签
var filterArr = [];
for(var i = 0;i
函数进阶
预解析
函数的两种申明
-
函数申明式
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即回调函数