循环
分支结构(选择结构)
- if
if结构
if(条件) {
条件成立时执行的语句
} else {
条件不成立时执行的语句
}
else必须和if搭配,但是可以省略即
if() {
}
if还可以使用多种判断条件
if() {
} else if() {
} else if() {
} ...
else {
}
if里面还可以嵌套着if
if() {
if() {
}
}
- switch
case :
break;
case :
break;
...
default :
break;
}
循环结构
- for循环
for(var i=1; i<=50; i++) {
console.log("第"+i+"次");
}
表达式1 var i = 1 表达式2 i<=50 循环条件 表达式3 i++ 三个表达式用分号隔开 循环体------大括号的语句(需要重复执行的语句)
执行流程: S1 先执行表达式1
S2 再执行表达式2,表达式2为真,继续S3假如表达式2为假,循环到此结束
S3 执行循环体
S4 S3完成后,执行表达式3 继续回到S2
- 循环嵌套
for(var i = 0;i<50;i++){
for(var j = 0;j<50;j++){
}
}
- break与continue
break用于switch或任何循环中,表示跳出相应的结构
continue只用于循环,结束本次循环继续下一次循环
- while循环
while(条件) {
循环体
}
循环体可能一次都不执行,因为条件可能一开始就不满足。
- do-while循环
do {
循环体
}while(条件);
循环体一定执行至少一遍
来个小demo吧
游戏开始,系统随机生成一个地雷数 1~100 比如68,系统提示请输入一个数字 范围1~100,用户输入45,系统提示 恭喜没有猜到地雷 下一个人接着猜 范围45~100 下一个输入78,系统提示恭喜没有猜到地雷 下一个人接着猜 范围45~78
假如输入的数字 比地雷数大 上限改成用户输入的数
假如输入的数字 比地雷数小 下限改成用户输入的数
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
var min_num = 0;
var max_num = 100;
var input_num = parseInt(prompt("请输入"+min_num+"~"+max_num+"的数字"));
var random_num = parseInt(Math.random()*100+1);
console.log(random_num);
while(input_num!=random_num){
if(input_num>random_num){
if (input_num>max_num) {
input_num = parseInt(prompt("请输入"+min_num+"~"+max_num+"的数字"));
continue;
}
max_num = input_num;
input_num = parseInt(prompt("请输入"+min_num+"~"+max_num+"的数字"));
}else if (input_num<random_num) {
if (input_num<min_num) {
input_num = parseInt(prompt("请输入"+min_num+"~"+max_num+"的数字"));
continue;
}
min_num = input_num;
input_num = parseInt(prompt("请输入"+min_num+"~"+max_num+"的数字"));
}
}
alert("恭喜你答对了,答案是"+random_num);
</script>
</body>
</html>
函数
函数定义和调用
function 函数名() {
// 函数体
}
函数名(); //调用函数
以上就是函数定义和函数的调用,切记函数的调用要加括号,不加括号只能表达函数这个对象。
函数意义
当大量程序相同时候,可以封装成一个function,这样封装一次,多次调用
函数的参数
function 函数名(参数1,参数2,参数3.....) {
// 函数体
}
函数的参数就是写在括号里面,可以是一个,两个,三个甚至是多个
function add(a,b) {
console.log(a+b);
}
add(10,10);
add(40,50);
函数的返回值
function sum(a,b) {
// 函数体------具体功能的实现
var c = a + b;
//console.log(c);
// 结果返回出去
return c; // 返回c的值
c++;//不执行
}
需要通过return去返回一个值,一旦有return返回值了,那么retuen后面的代码就都不执行。
函数表达式
函数表达式也是定义函数的一种方式 比如
var sum = function(num1,num2) {
return num1 + num2;
}
等号右边的可以是一个没有名字的函数(匿名函数),也可以是一个有函数名的函数
函数声明提升(预解析)
有参数声明提示,肯定也有函数声明提升。
情况1:
alert(a());
function a(){alert(1)};
则会出现弹框内容是1,因为js会将所有函数声明进行提升,即使函数声明在函数调用之后,也不会报错,也能正常的解析函数。若此时alert(a),弹出的不是结果而是整个函数的内容了。所有调用函数要加括号。
情况2:
alert(a());
var a = function(){
alert(1);
};
会报错提示找不到函数a,因为函数表达式不会被提升,
情况3:
fun();
var fun;
function fun() {
alert(1);
}
fun = function() {
alert(2);
}
此时弹框的内容是1,不是2,函数优先 遇到同名标识符 预解析阶段一定把这个标识符给函数。
若是下面顺序
var fun;
fun = function() {
alert(2);
}
fun(); // 显示2
function fun() {
alert(1);
}
若在调用方法前,已经声明了函数,则就不会去调用预解析中同名的方法。
函数也是引用类型
什么是引用类型呢?引用类型是是一种将数据和功能组织在一起的数据类型。我们可以给该数据类型添加属性,方法等。
var fun = function() {
alert("ok");
}
//alert(typeof fun);// function也是一种类型 属于引用类型的一种
var fun2 = fun;
fun2.aa = 10; //
console.log(fun.aa);//10
fun2.aa++;
fun2.aa++;
console.log(fun.aa); // 12
fun2();
我们来看看,我们将fun函数对象赋予了fun2,并且给fun2对象添加了一个aa属性并且赋值于10,之后对aa进行递增,最后显示的值是12,我们还能去调用方法。这些操作很符合应用类型的定义,是一个将数据和功能组织在一起的数据类型。
作用域
函数能够封闭住定义域
function fun() {
var num = 10;
console.log("我是函数里的语句,我可以认识num,它的值为"+num);
}
fun();
console.log(num);//报错
那么编译时就会报错,因为num是个变量被函数封闭住了,可以说num变成了局部变量,在函数以外是访问不到的,所以在log的时候报错找不到num的错误
总结一下作用于
- 在函数内部通过var定义的变量叫局部变量,使用有效范围在函数里面
- js变量作用域非常简单,没有块级作用域,只有函数可以管理住作用域
- 函数外定义的变量 是全局变量,都认识
作用域链
什么叫作用域链?我更理解为是一个动词,它表示的是在一个父函数中嵌套这子函数,子函数在使用参数时,会逐级往上找,这么个动作称之为作用域链。
var a = 1;
var b = 2;
function outer() {
var a = 3;
function inner() {
var b = 4;
conosle.log(a); (1)
conosle.log(b);(2)
}
inner();
conosle.log(a); (3)
conosle.log(b); (4)
}
outer();
conosle.log(a); (5)
conosle.log(b); (6)
我们来分析一下这6处的输出的值。
(1)输出3,在inner函数中没有a这个参数,所以就往上找,找到父亲outer中的3并显示出来
(2)输出4,因为在inner函数中就有b这个参数,故显示4
(3)输出3,直接找到了自己(outer)的函数体中的参数a,显示3
(4)输出2,因为在自己(outer)的函数体中没有b这个参数,故只能往全局变量中找,显示2
(5)输出1,该log在函数体外,故在全局变量中找,显示1
(6)输出2,同5,在全局变量中找,显示2
隐式全局变量
隐式全局变量,就是不写var的变量自动变成全局变量
function fn() {
b = 12; // 没有通过var去定义b
}
fn();
console.log(b); // 12
在函数中没有用var去定义b,那么b就是全局变量,显示12还不会报错。
函数参数,默认定义为局部变量
function fun(a,b,c) {
// 相当于 var a,b,c
}
那么a,b,c就是该函数的局部变量,只限在函数体里使用。
函数定义也有作用域
这句话怎么理解呢?就是父函数内定义了个子函数,在父函数外去调用子函数,那么调用时一定报错,因为子函数此时可以理解为一个局部变量,外部当然访问不到,也获取不到。若一定要访问,可通过return子函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
// 返回a的平方与b的平方和
function pingfanghe(a,b) {
return pingfang(a)+pingfang(b);
// 返回m的平方
function pingfang(m) {
return Math.pow(m,2);
}
}
var res = pingfanghe(3,4);
var res2 = pingfang(6); // 报错 因为离开外面函数没有作用域
</script>
</body>
</html>
我们来分析一下,var res = pingfanghe(3,4);这含代码是不会报错的,同时也达到目的去调用pingfang的函数,因为父函数通过return的形式去返回一个pingfang函数。然而var res = pingfanghe(3,4);直接调用了内部的函数,此时被调函数的作用域只在pingfanghe内,故会报错。
闭包
其实上述问题就是一个闭包。那么什么是闭包。先上代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
function outer() {
var num = 666;
function inner() {
console.log(num);
}
return inner; // outer函数返回 inner的引用
}
var inner = outer();
inner();// 666
</script>
</body>
</html>
就因为函数也是有作用域的,所以我们想要获取到内部函数,需要通过外部函数去retuen获得。因为闭包我们才需要这么做。
先来个简单的理解闭包:一个函数可以把它自己内部的语句,和自己声明时所处的作用域一起封装成了一个密闭的环境,我们称为"闭包"。因为函数的闭包,inner和num被封装在outer的密闭的环境里,因为实在密闭的环境里,所以在outer函数的外部我们是不能直接访问到inne函数。
再来个稍微复杂点的理解闭包:Javascript允许使用内部函数---即函数定义和函数表达式位于另一个函数的函数体内。而且,这些内部函数可以访问它们所在的外部函数中声明的所有局部变量、参数和声明的其他内部函数。当其中一个这样的内部函数在包含它们的外部函数之外被调用时,就会形成闭包。
每个函数都是闭包,每个函数都天生可以记住定义时所处的作用域。怎么理解看看下面的demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
var inner;// 全局变量
function outer() {
var num1 = 260;
var num2 = 360;
// inner变成一个函数
inner = function() {
alert(num1);
alert(num2);
}
}
outer();
var num1 = 300;
var num2 = 100;
inner(); // 260 360
</script>
</body>
</html>
我们来看看上面的那个例子,最后的弹框内容是260 360,虽然函数体外定义了同名的num1 num2,但是由于闭包,inner记住了声明时所处的定义域,所有弹出的内容是260 360.
每次重新声明函数,闭包都是新的
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script type="text/javascript">
function outer() {
var count = 0;
function inner() {
count++;
console.log(count);
}
return inner;
}
var inn1 = outer();
var inn2 = outer();
inn1();// 1
inn1();// 2
inn1();// 3
inn2();// 1
inn2();// 2
inn2();// 3
</script>
</body>
</html>
我们可以看到inn1 和 inn2第一次调用都是1,也就是说每一次重新声明函数都是新的,并没有接着上一个函数内参数值继续做自增。