变量提升
原因
js运行的三个阶段:
1.预编译
2.预解析
3.执行代码
----------------------------------------
在预解析阶段,
console.log(num);// undefined
var num = 10;
会把 var num ;提升到最上面,而不提升值
---------------------------------------------
对变量的提升
系统直接赋underfined
对函数的提升
JS语言对函数也一样会执行提升操作,但是提升的思路并不像变量那么简单粗暴。
对函数的提升就是将整个函数都赋值给函数名,至于函数内部有什么东西则完全不管。
// JS对于函数的提升相当于是有名函数赋值表达式
// fn = function fn(){ alert(1) }
fn();// 可以执行
function fn(){ alert(1) };
let和var区别
ES6 新增了let命令,用来声明局部变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效,而且有暂时性死区的约束。
---------------------
ES6可以用let定义块级作用域变量
在ES6之前,我们都是用var来声明变量,而且JS只有函数作用域和全局作用域,没有块级作用域,所以{}限定不了var声明变量的访问范围。
{
var i = 9;
}
console.log(i); // 9
\---------------------
let i = 9; // i变量只在 花括号内有效!!!
}
console.log(i); // Uncaught ReferenceError: i is not defined
let 配合for循环的独特应用
let非常适合用于 for循环内部的块级作用域。JS中的for循环体比较特殊,每次执行都是一个全新的独立的块作用域,用let声明的变量传入到 for循环体的作用域后,不会发生改变,不受外界的影响。看一个常见的面试题目:
for (var i = 0; i <10; i++) {
setTimeout(function() { // 同步注册回调函数到 异步的 宏任务队列。
console.log(i); // 执行此代码时,同步代码for循环已经执行完成
}, 0);
}
// 输出结果
10 共10个
// 这里面的知识点: JS的事件循环机制,setTimeout的机制等
如果把 var改成 let声明:
// 虽然在全局作用域声明,但是在for循环体局部作用域中使用的时候,变量会被固定,不受外界干扰。
for (let i = 0; i < 10; i++) {
setTimeout(function() {
console.log(i); // i 是循环体内局部作用域,不受外界影响。
}, 0);
}
// 输出结果:
0 1 2 3 4 5 6 7 8 9
let没有变量提升与暂时性死区
用let声明的变量,不存在变量提升。而且要求必须 等let声明语句执行完之后,变量才能使用,不然会报Uncaught ReferenceError错误。
例如:
console.log(aicoder); // 错误:Uncaught ReferenceError ...
let aicoder = 'aicoder.com';
// 这里就可以安全使用aicoder
变量重名
当变量名和函数名重合时,
在提升阶段变量名和函数名重名,函数优先。
在执行阶段变量名和函数名重名,变量优先。
变量的作用域(生命周期)
局部变量
只能在函数内部使用,只能再函数内部被访问
随着函数的执行完毕而销毁
全局变量
定义在函数内部,始终在内存中,随着页面的关闭而销毁
定义在函数外部,在页面的任何位置都能被访问
局部变量和全局变量区别
当全局变量域局部变量重名的时候优先使用局部变量。
全局变量的优点:
省心省力
有效的减少变量的个数(当多个函数用到同一个值一个全局变量就能搞定)
全局变量的缺点:
关于全局的缺点非常多,这里我们只给大家总结几个常见的:
变量污染:变量名之间的相互覆盖
增加函数之间的耦合性:函数之间相互依赖
内存压力:因为一直保存在内存中,即便是不需要的时候也会一直存在,不利于内存空间的合理利用
通过匿名函数自执行的方式就能够有效的避免变量污染的问题,如果出现了需要把一些数据拿给别人用的情况可以使用函数的返回值。
递归
递归:函数调用自身
递归和循环区别:
递归的特点:重复计算执行,和循环非常类似。所以递归也和循环一样,需要一个出口。
性能不如循环
内存占用过高(非常致命)
递归次数必须预期收敛
确定递归边界和递归公式
// 打印斐波那契数列
1,1,2,3,5,8,13,21,34....
function f(x){
var num ;
num = x<3 ? 1: ( f(x-1)+f(x-2));
return num ;
}
for(var i = 1 ; i<=10; i++){
var result = f(i);
document.write( result +" ");
}
// 求10的阶乘
function fn(num){
if(num>=10) return num;
return num *= fn(++num);
}
var result = fn(1);
console.log(result);
递归边界可以是一个for循环遍历
也可以是if的判断
递归公式可以是普通的公式,但是记得调用哪个参数,加上f( 参数 )即可
回调函数
回调函数:不会立即执行的函数,满足一定的条件才会执行或者由别的代码来执行的函数,可以理解为做计划。
-----------------------------------<!-- 1.写结构 -->
// 2.获取页面中的元素+-*/span
var jia = document.getElementById("jia");
//3.定义一个函数
function f( r){}
//4.获取两个输入框的值
var n1 = +document.getElementById("n1").value;
//5.通过switch选择
switch(r){
case "+":
result = n1+n2 ;break;
//6.获取span中的元素
var j = document.getElementById("span");
//7.在span中放入值
j.innerText = result;
//8.通过点击事件,用匿名函数调用上面函数
jia.onclick = (function(){
f("+");
});
作业
// 求10的阶乘
// 打印斐波那契数列
// 1,1,2,3,5,8,13,21,34....
// 求最大公约数
// 求最小公倍数
// 辗转相除法
//计算器
答案
// // 求10的阶乘
function fn(num){
if(num>=10) return num;//递归边界
return num *= fn(++num);//num= num*fn(++num),num= 1*fn(2)=>
}
var result = fn(1);
console.log(result);
function fn(num){
if(num >=10) return num;//递归边界
// return num *= fn(++num);//1 = 1*fn(2)/ 1*2*fn(3)/ 1*2*3*fn(4)
// return num += fn(++num)
}
let result = fn(1);
console.log(result);
// // 打印斐波那契数列
// 1,1,2,3,5,8,13,21,34....
function f(x){
var num ;
num = x<3 ? 1: ( f(x-1)+f(x-2));
return num ;
}
for(var i = 1 ; i<=10; i++){
var result = f(i);
document.write( result +" ");
}
// 求最大公约数,a除以b,如果余数c为0,b就是最大公约数,否则再将b除以余数c,直到c= 0
function f(a,b){
let num =a%b ;
if( num === 0) return b;
num = f(b, a%b)
return num
}
var result = f(6,50);
console.log(result);
function f(a,b){
var num = a % b;
if( num === 0) return b;
else{
// num = f(b) % f(a%b);错误写法!!!注意咯
num = f(b , a%b);//正确写法!!!
}
return num;
}
var num1 = +prompt("请输入大数");
var num2 = +prompt("请输入小数");
var result = f(num1,num2);
console.log(result);
// 求最小公倍数 :两个数相乘除以最大公约数;
function f(a,b){
if(a>b){
var num = a % b;
var sum = 0;
if( num === 0) return b;
else{
// num = f(b) % f(a%b);错误写法!!!注意咯
num = f(b,a%b);//正确写法!!!
}
sum = (a * b )/num;
console.log(a,b);
return sum;
}
else{
document.write("请输入正确的数字!");
}
}
var num1 = +prompt("请输入大数");
var num2 = +prompt("请输入小数");
var result = f(num1,num2);
console.log(result);
//计算器
// 打印斐波那契数列
function f(a,b){
if(b >7) return ;
document.write(a + " ",b+ " ");
return f(a+b,a+2*b) ;
}
f(1,1);