小黑子的JavaScript入土过程第二章
JavaScript系列教程第二章
2.1 do…while 循环语句
do{
语句...
}
while(条件表达式)
-执行流程:
do. . . while语句在执行时,会先执行循环体,
循环体执行完毕以后,在对while后的条件表达式进行判断,
如果结果为true,则继续执行循环体,执行完毕继续判断以此类推
如果结果为false,则终止循环
实际上这两个语句功能类似,不同的是while是先判断后执行,
而do.. .while会先执行后判断
与while语句的区别:
do. . . while可以保证循环体至少执行一次,
而while不能
2.2 for 循环语句
在for循环中,为我们提供了专门的位置用来放三个表达式:
1.初始化表达式
2.条件表达式
3.更新表达式
for循环的语法:
for (③初始化表达式;@条件表达式;@更新表达式)
{
③语句...
}
for循环的执行流程:
①执行初始化表达式,初始化变量
②执行条件表达式,判断是否执行循环。
如果为true,则执行循环③
如果为false,终止循环
④执行更新表达式,更新表达式执行完毕继续重复②
注意:
for循环中的三个部分都可以省略,也可以写在外部
如果在for循环中不写任何的表达式,只写两个;
此时循环是-一个死循环会一直执行下去, 慎用
for( ; ; )
{
语句;
}
质数练习:
-判断质数
<script type="text/javascript">
var number=prompt("请输入一个整数:");
if(number<=1)
{
alert("该数不合法!!!");
}
else
{
var flag =true;
for(var i=2;i<number;i++)
{
if(number % i ==0)
{
flag = false;
break;
}
}
if(flag)
{
alert(number+"是质数");
}
else
{
alert(number+"不是质数");
}
}
</script>
-输出2-100内的所有质数
<script type="text/javascript">
//打印2-100之间所有的数
for(var i=2;i<=100;i++)
{
//创建一个布尔值,用来保存结果,默认i是质数
var flag =true;
// 获取到2- i之间的所有的数
for(var j=2;j<i;j++)
{
// 判断i是否能被j整除
if( i % j ==0 )
// 如果进入判断则证明i不是质数,修改flag值为false
{
flag = false;
break;
}
}
// 如果是质数,则打印i的值
if(flag)
{
console .log(i);
}
}
</script>
—>
2.3 嵌套的 for 循环
通过一个for循环来输出图形
- 这个for循环执行几次,图形的高度就是由i来控制
- 它可以用来控制图形的高度
在循环的内部再创建一个循环, j用来控制图形的宽度
-目前我们的外部的for循环执行1次,内部的就会执行5次
-内层循环可以来决定图形的宽度,执行几次图形的宽度就是多少
<script type="text/javascript">
for(var i=0 ; i<5 ; i++)
{
for(var j=0 ; j<i+1; j++)
{
document . write("* ");
}
// 输出一个换行
document . write("<br />");
}
</script>
—>
2.
<script type="text/javascript">
for(var i=0 ; i<5 ; i++)
{
for(var j=0 ; j<5-i; j++)
{
document . write("* ");
}
// 输出一个换行
document . write("<br />");
}
</script>
—>
2.4 break 结束循环语句
break关键字可以用来终止switch或while,do…while,for等整个循环语句
不能在if语句中使用break和continue
break关键字,会立即终止离他最近的那个循环语句
例如:
<script type="text/javascript">
for(var i=0 ; i<5 ; i++)
{
console .log("@外层循环"+i);
for(var j=0 ; j<5; j++)
{
break;
console .log("内层循环:"+j);
}
}
</script>
—>
如果想要也要外面也终止
1.可以为循环语句创建一 个名字比如:label,来标识当前的循环
2.label :循环语句
3.使用break语句时,可以在break后跟着一个label,
4.这样break将会结束指定的循环,而不是最近的
<script type="text/javascript">
label:
for(var i=0 ; i<5 ; i++)
{
console .log("@外层循环"+i);
for(var j=0 ; j<5; j++)
{
break label;
console .log("内层循环:"+j);
}
}
</script>
—>
2.5 continue 跳出循环语句
continue关键字可以用来跳过 当次循环 !
同样,continue也是默认只会对离他最近的循环循环起作用
测试如下的程序的性能
-在程序执行前,开启计时器:
console. time (“计时器的名字“)可以用来开启一个计时器
它需要一 个字符串作为参数,这个字符串将会作为计时器的标识
-终止计时器:
console. timeEnd( )用来停止一个计时器,需要-个计时器的名字
作为参数
范例:
<script type="text/javascript">
console .time("test");
for(var i=2;i<=100;i++)
{
var flag =true;
for(var j=2;j<i;j++)
{
if( i % j ==0 )
{flag = false;}
}
if(flag)
{
console .log(i);
}
console .timeEnd("test");
}
</script>
—> 浏览器 执行时间
3.6 初识函数 function
函数 function 是一个复杂的数据类型
1. 定义函数
(1)声明式:先调用再定义
function test1(){
console.log("我是test1套餐")}
function test2(){
console.log("我是test2套餐")}
(2) 赋值式:先定义再调用
var test3 = function(){
console.log("我是test3套餐")}
2.调用函数
test1()
test2()
test3()
3.6.1 函数的参数
3.6.2 函数返回return
return返回的意思,其实就是给函数一个返回值用来终断函数
函数调用本身也是一个表达式,表达式就应该有一个值出现
比如:
现在的函数执行完毕之后,是不会有结果出现的
加了return关键字就是可以给函数执行完毕一个结果
3.6.3 函数预解析
●预解析其实就是聊聊js代码的编译和执行,将变量声明提升到前面
●js是一个解释型语言,就是在代码执行之前,先对代码进行通读和解释,然后在执行代码
●也就是说,我们的js代码在运行的时候,会经历两个环节解释代码和执行代码
解释代码
●因为是在所有代码执行之前进行解释,所以叫做预解析(预解释)
●需要解释的内容有两个
-声明式函数function
■在内存中先声明有一个变量名是函数名,并且这个名字代表的内容是一个函数
-var关键字
■在内存中先声明有一个变量名
1.声明式变量赋值时案例
<script>
console.log(my)
var myname="steve"
console.log(myname)
</script>
在定义前要求输出没有定义的my,显然报错
但是
<script>
console.log(myname)
var myname="steve"
console.log(myname)
</script>
在定义前要求输出有定义的myname,却没有报错
这是由于js定义变量时会把声明这个部分先提到前面去预读,符合输出的名字,可是第一个输出在实际中却是在定义前面,故无法赋值,所以就变成了没有定义而不报错的现象。
- 声明赋值函数时案例
<script>
var myname=function(){
console.log("steve")
}
myname()
</script>
显然符合没有报错
但是把myname()提到赋值函数前面时
<script>
<script>
myname()
var myname=function(){
console.log("steve")
}
myname()
</script>
</script>
于前面案例1不同的时,竟然没有出现未定义,而是直接报错了
案例1的第一个要求输出的my没有对下面定义名产生影响,而案例2因为第一个设置的myname是未定义的,而下面要求对undefined的myname定义成函数,但是未定义是不能成为函数的,所以就报错了。
- 声明式函数案例
<script>
myname()
function myname(){
console.log("steve")
}
myname()
</script>
在声明式函数中,第一个未定义的在前面竟然没有和案例2一样报错。是因为在预解析中,声明函数会提到最前面进行预读,对myname进行了声明成为了函数,而不是像案例2一样将未定义声明成函数。既然已经成为了函数,那么就会输出内容
3.6.4 重名问题
一、输出打印重名
1.打印在前
<script>
console.log(age)
var age=100
function age(){
console.log("age is 100")
}
</script>
js进行预读,先预读赋值定义的内容但是前面输出age实际是在赋值定义前面的,所以未能起到定义成100的效果。然后,再预读声明函数对age进行了声明成为了函数,,所以输出了声明函数的内容。
2.打印在后
<script>
var age=100
function age(){
console.log("age is 100")
}
console.log(age)
</script>
先预读赋值定义,再预读声明函数,由于这次age实际在赋值定义的后面,又是先预读赋值,就不在继续输出声明函数的内容,故输出了100
二、调用函数重名
1.调用函数在前面
<script>
age()
var age=100
function age(){
console.log("age is 100")
}
console.log(age)
</script>
先预读赋值定义,再预读声明函数,由于在前面设置了同名调用函数age(),会直接输出声明函数的内容,就与同名赋值100无关了。
2.调用函数在后面
<script>
var age=100
function age(){
console.log("age is 100")
}
console.log(age)
age()
</script>
先预读赋值定义,再预读声明函数,由于调用函数age()实际在赋值定义后面,又是先预读同名赋值,所以age这个名就被定义了,就不能再成为函数被调用,故报错了。
3.7 九九乘法表实现案例
3.7.1 利用for循环嵌套
<script>
for(var i=1;i<=9;i++)
{
for(var j=1;j<=i;j++)
{
document.write("<span>"+i+"*"+j+"="+i*j+"</span>")
}
document.write("<br>")
}
</script>
<style>
span{
display: inline-block;
width: 80px;
line-height: 30px;
}
</style>
3.7.2 函数实现
<script>
function test(target){
if(target===undefined){
alert("请输入参数")
console.log("请输入参数")//判断test()是否空
}
for(var i=1;i<=target;i++)
{
for(var j=1;j<=i;j++)
{
document.write("<span>"+i+"*"+j+"="+i*j+"</span>")
}
document.write("<br>")
}
}
test(9)
test(5)
test(8)
test(6)
</script>
<style>
span{
display: inline-block;
width: 80px;
line-height: 20px;
}
</style>
2.8 运算符的优先级
就和数学中一样,在JS中运算符也有优先级,
比如:先乘除后加减
在JS中有一个运算符优先级的表,
在表中越靠上优先级越高,优先级越高越优先计算,
如果优先级一样,则从左往右计算。
但是这个表我们并不需要记忆,如果遇到优先级不清楚
可以使用( )来改变优先级
例如:
','运算符
使用','可以分割多个语句,一般可以在声明多个变量时使用 ','
使用','运算符可以同时声明多个变量并赋值
<script>
var a=1,b=2,c=3;
</script>
2.9 代码块
我们的程序是由一条一条语句构成的
语句是按照自,上向下的顺序一条一条执行的
在JS中可以使用{ }来为语句进行分组,
同一个{ }中的语句我们称为是一组语句,
它们要么都执行,要么都不执行,
一个{ }中的语句我们也称为叫一个代码块
在代码块的后边就不用再编写 ; 了
JS中的代码块,只具有分组的的作用,没有其他的用途
代码块内容的内容,在外部是完全可见的
例如:
<script>
{
var a=10;
alert("hello");
console.log("你好");
document.write("语句");
}
</script>
2.10 流程控制语句
流程控制语句
- JS中的程序是从上到下一行一行执行的
-通过流程控制语句可以控制程序执行流程,
使程序可以根据一定的条件来选择执行
-语句的分类:
1.条件判断语句
2.条件分支语句
3.循环语句
2.11 对象的简介
JS中数据类型
String字符串
Number数值
Boolean布尔值
Null空值
- Undefined 未定义
-以上这五种类型属于基本数据类型,以后我们看到的值
只要不是上边的5种,全都是对象
- object对象
-
基本数据类型都是单一的值"hello" 123 true,
值和值之间没有任何的联系。
在JS中来表示一个人的信息(name gender age):
var name ="孙悟空" ;
var gender ="男" ;
var age = 18;
如果使用基本数据类型的数据,我们所创建的变量都是独立,
不能成为一个整体。
对象属于一种复合的数据类型,在对象中可以保存多个不同数据
类型的属性。
对象的分类:
1.内建对象
由ES标准中定义的对象,在任何的ES的实现中都可以使用
-比如: Math String Number Boolean Function Object...
2.宿主对象
由JS的运行环境提供的对象,目前来讲主要指由浏览器提供的对象
-比如 BOM DOM
3.自定义对象
-由开发人员自己创建的对象
2.12 对象的基础操作
-创建对象
使用new关键字调用的函数,是构造函数constructor
构造函数是专门用来创建对象的函数
使用typeof检查一个对象时,会返回object
在对象中保存的值称为属性
向对象添加属性
语法: 对象.属性名=属性值;
-读取对象
语法: 对象.属性名
-修改对象的属性值
语法:对象.属性名=新值
-删除对象的属性
语法: delete 对象.属性名
示例:
1.
<script type="text/javascript">
var obj = new Object;
obj.name="叼德一";
obj.gender="man";
obj.age=520;
console .log(obj)
</script>
</head>
—>
2.
<script type="text/javascript">
var obj = new Object;
obj.name="叼德一";
console .log(obj.name)
obj.gender="man";
console .log(obj.gender)
obj.age=520;
delete obj.age
console .log(obj.age)
</script>
—>
2.13 作用域
什么是作用域,就是一个变量可以生效的范围
变量不是在所有地方都可以使用的,而这个变量的使用范围就是作用域
3.13.1 全局作用域
●全局作用域是最大的作用域
●在全局作用域中定义的变量可以在任何地方使用
●页面打开的时候,浏览器会自动给我们生成一个全局作用域wi ndow
●这个作用域会一直存在,直到页面关闭就销毁了
<script>
var myname="steve"
</script>
<script>
console.log(myname)
</script>
前提是在下一个script标签下没有继续定义,那么便可以继承
3.13.2 局部作用域
●局部作用域就是在全局作用域下面有开辟出来的一个相对小一些的作用域
●在局部作用域中定义的变量只能在这个局部作用域内部使用
●在JS中只有函数能生成一个局部作用域,别的都不行
●每一个函数,都是一个局部作用域
<script>
var myname="steve"
function test(){
console.log(nickname,myname)
var nickname = "xiaoming"
console.log("test=",nickname)
}
</script>
<script>
console.log(myname)
test()
</script>
在声明函数里,由于局部声明变量预读提升,nickname有了定义,而由于函数里并没有myname定义,所以是undefined,但是又有全局定义在函数之外,所以会显示steve。
3.13.3 作用域访问规则
●当我想获取一个变量的值的时候,我们管这个行为叫做访问
●获取变量的规则:
。首先,在自己的作用域内部查找,如果有,就直接拿来使用
。如果没有,就去上一级作用域查找,如果有,就拿来使用
。如果没有,就继续去上一级作用域查找,依次类推
。如果一直到全局作用域都没有这个变量,那么就会直接报错(该变量is not defined)
赋值规则
●当你想给一个变量赋值的时候,那么就先要找到这个变量,在给他赋值
●变量赋值规则:
。先在自己作用域内部查找,有就直接赋值
。没有就去.上一级作用域内部查找,有就直接赋值
。还没有再去上一级作用域查找,有就直接赋值
。如果一直找到全局作用域都没有,那么就把这个变量定义为全局变量,再给他赋值
3.14 对象数据类型
对象
●对象是一个复杂数据类型
●其实说是复杂,但是没有很复杂,只不过是存储了一些基本数据类型的一个集合
例如:
var obj={
num: 100,
str: 'he11o wor1d'
}
●这里的{}和函数中的{}不一样
●函数里面的是写代码的,而对象里面是写一些数据的
●对象就是一个键值对的集合
●{}里面的每一个键都是一个成员
●也就是说,我们可以把一些数据放在一个对象里面, 那么他们就互不干扰了
●其实就是我们准备一个房子,把我们想要的数据放进去,然后把房子的地址给到变量名,当我们需要某一个数据的时候,就可以根据变量名里面存储的地址找到对应的房子,然后去房子里面找到对应的数据
3.15.1 字面量的方式创建一个对象
//创建一个空对象
var obj = {}
//像对象中添加成员
obj. name =‘Jack'
obj.age = 18
3.15.2 内置构造函数的方式创建对象
//创建一个空对象
var obj = new object()
//向对象中添加成员
obj. name ="Rose"
obj.age = 20
。object是js内置给我们的构造函数,用于创建一个对象使用的
3.16 对象的基本操作
一、定义的对象名.成员写法
增
//增加对象成员的形式就是继续增添定义的对象名.成员=
var obj = {}
obj.name = "kerwin"
obj.age = 100
obj .location = "dalian"
console. log(obj)
删
//删:delete关键字
// obj.name =" "空的字符串并不能起到删除对象里的成员效果
delete obj . name
console . log(obj)
改
//从上到下,依次执行,改成的同最终结果
var obj = {}
obj.name = "kerwin"
obj.age = 100
obj .location = "dalian"
obj . age= 200
console . log( obj)
查
//查:在浏览器的页面可查询
document . write("姓名是"+ obj . name )
二、定义的对象名[" "]写法
同一的增删改查一样,只不过换个写法
三、不符合命名规则写法
var myobj = {
a+b" : "111111" ,
"#aa":"222222"
}
// console. log(myobj."a+b") 无法打印识别
console. log(myobj["a+b"]) 不符合命名规则的正确打印写法
3.17 对象的遍历
使用 for in 遍历对象的属性,直接传入对象名即可,for in 返回的每一个元素时对象的键(成员名)而不是值(成员的值)。
案例:
这样输出打印就比较麻烦
var obj={
name: " kerwin",
age: 100 ,
location:"dalian",
}
document .write("name:"+ obj . name )
document.write("<br>")
document . write("age:"+ obj .age)
document.write("<br>")
document . write("location:"+ obj . location)
document . write("<br>")
可以利用for循环输出
var obj={
name: " kerwin",
age: 100 ,
location:"dalian",
a:1
b:2
}
for (var i in obj ){
// 获取key
// console.log(i)
// 获取value
// document . write(obj[i])
document . write(i+":"+obj[i])
document . write("<br>")
}
3.18 不同数据类型的储存
案例1:
<script>
var obj1={
name:"steve",
age:100
}
var obj2=obj1
console.log(obj1===obj2)
obj2.name="van"
console.log(obj1,obj2)
</script>
obj1和obj2相等了,那么说明它们用了相同的地址引入相同的内容。故obj2改了name,obj1也就跟着变了
原理:
案例2:
同上面不同,这次定义两个相同内容的键,但是实际上它们不相等,是因为它们地址不同了。
<script>
var obj1={name:"steve"}
var obj2={name:"steve"}
console.log(obj1===obj2)
</script>
因此判断报错
-数据类型之间存储的区别
●既然我们区分了基本数据类型和复杂数据类型
●那么他们之间就一定会存在一些区别
●他们最大的区别就是在存储上的区别
●我们的存储空间分成两种栈和堆
●栈:主要存储基本数据类型的内容
●堆:主要存储复杂数据类型的内容
案例3:
利用遍历实现两个对象内容相等,优势在于方便更改内容
<script>
var obj1={
name:"steve",
age:100,
location:"magua",
a:1,
b:2
}
var obj2={}
for(i in obj1){
obj2[i]=obj1[i]//利用遍历将obj1中的每个值取出来放给obj2中
}
obj2.name="van"
console.log(obj1,obj2)
</script>
3.19 数组
●什么是数组?
●字面理解就是数字的组合
●其实不太准确,准确的来说数组是一个数据的集合
●也就是我们把一 些数据放在一 个盒子里面,按照顺序排好
[1, 2,3,‘he11o’, true, false]
●这个东西就是一个数组,存储着一 些数据的集合
数据类型分类
●number / string 1 boolean 1 undefined / nu111 object / function / array / ...
●数组也是数据类型中的一种
●我们简单的把所有数据类型分为两个大类基本数据类型和复杂数据类型
●基本数据类型: number 1 string 1 boolean 1 undefined 1 nu11
●复杂数据类型: object 1 function 1 array 1..
数组的索引
-指的是数组中元素的索引就是该元素在数组中的下标。 由于数组下标从0开始,所以元素的下标为该元素所在的位置-例如:var arr []= {1,2,3,4,5}; 1这个元素在arr这个数组中索引为0,2就是索引1,依次类推。
3.19.1 数组的基本操作
一、利用length清空数组内容
length:调节数组长度时,保留前面的,删去后面的
<script>
var arr1=[1,2,3,4,5]
arr1.length=3
console.log(arr1)
// 清空数组
arr1.length=0
console.log(arr1)
</script>
二、利用for循环输出数组内容
<script>
var arr3 =[3,4,5,6,7,8]
for(var i=0;i<arr3.length;i++)
{
console.log(arr3[i])
}
</script>
3.20 冒泡排序
思路:
●先遍历数组,让挨着的两个进行比较,如果前一个比后一个大,那么就把两个换个位置
●数组遍历-遍以后,那么最后一个数字就是最大的那个了
●然后进行第二遍的遍历,还是按照之前的规则,第二大的数字就会跑到倒数第二 的位置
●以此类推,最后就会按照顺序把数组排好了
1.我们先来准备一一个乱序的数组
var arr=[3,1,5,6,4,9,7,2,8]
接下来我们就会用代码让数组排序
2.先不着急循环,先来看数组里面内容换个位置
//假定我现在要让数组中的第0项和第1项换个位置
//需要借助第三个变量
var tmp = arr[0]
arr[0] = arr[1]
arr[1] = tmp
3.第一次遍历数组,把最大的放到最后面去
for(vari=0;i<arr.length;i++){
//判断,如果数组中的当前一个比后一个大, 那么两个交换一下位置
if (arr[i] > arr[i + 1])
{
var tmp = arr[]
arr[] = arr[i + 1]
arr[i + 1] = tmp
}
}
//遍历完毕以后,数组就会变成[3, 1,5,6,4, 7, 2,8,9]
■第一次结束以后,数组中的最后-个,就会是最大的那个数字
■然后我们把上面的这段代码执行多次。数组有多少项就执行多少次
4.按照数组的长度来遍历多少次
for(varj=0;j<arr.length;j++)
{
for(vari=0;i<arr.length;i++)
{
// 判断, 如果数组中的当前一 一个比后-一个大, 那么两个交换 -下位置
if (arr[i] > arr[i + 1])
{
var tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
}
}
}
//结束以后,数组就排序好了
5.给一些优化
■想象一个问题,假设数组长度是9,第八次排完以后
■后面八个数字已经按照顺序排列好了,剩下的那个最小的一定是在最前面
■那么第九次就已经没有意义了,因为最小的已经在最前面了,不会再有任何换位置出现了
■那么我们第九次遍历就不需要了,所以我们可以减少一次
for(varj=0;j<arr.1ength-1;j++)
{
for (var i = 0; i < arr.1ength; i++)
{
//判断,如果数组中的当前一个比后一个大,那么两个交换一下位置
if (arr[] > arr[i + 1])
{
var tmp = arr[]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
}
}
}
■第二个问题,第一次的时候,已经把最大的数字放在最后面了
■那么第二次的时候,其实倒数第二个和最后一个就不用比了
■因为我们就是要把倒数第二大的放在倒数第二的位置,即使比较了,也不会换位置
■第三次就要倒数第三个数字就不用再和后两个比较了
以此类推, 那么其实每次遍历的时候, 就遍历当前次数-1次
for(varj=0;j<arr.length-1;j++)
{
for(vari=0;i<arr.1ength-1-j;i++)
{
//判断,如果数组中的当前一个比后-一个大,那么两个交换一下位置
if (arr[i] > arr[i + 1])
{
var tmp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tmp
}
}
}
6.至此,一个冒泡排序就完成了
案例:
<script>
var arr = [1, 321, 84, 4, 651, 4651, 5, 64, 4, 65, 1, 65, 44, 1, 4, 65, 1, 15, 6, 651]
// 外循环控制的是j值在内循环变化,可以让内循环依次交换完最大值后减少一次循环交换
for (j = 0; j < arr.length; j++)//减1的目的是让j少自增1,假如i=1,那么i+1=2,arr[2]是未定义的
{
for (var i = 0; i < arr.length - 1 - j; i++) //内循环控制值与值之间的交换
{
if (arr[i] > arr[i + 1]) {
var temp = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = temp
}
}
}
console.log(arr)
</script>
3.21 选择排序
<script>
var arr = [1, 321, 84, 4, 651, 4651, 5, 64, 4, 65, 1, 65, 44, 1, 4, 65, 1, 15, 6, 651]
for(var j=0;j<arr.length-1;j++)
{
var min=j
for(var i=j+1;i<arr.length;i++)
{
if(arr[i]<arr[min])
{min=i}
}
if(min!==j)
{
var temp=arr[j]
arr[j]=arr[min]
arr[min]=temp
}
}
console.log(arr)
</script>