目录
一、循环数组
当我们访问数组时,是通过下标去访问的,访问第二个(下标1)、第五个(下标6)、第七个(下标6),如果想访问每一个元素,就是每一个下标都写一遍,最大下标为数组长度减一。
当已知开始条件和结束条件,功能一样只需改变一个值时,可以想到for循环,对应为开始条件为0,表示第一个元素,结束条件为等于数组长度,然后利用循环增加下标,去访问每一个元素。这也就是数组的遍历。
<script>
var arr=['hello',23,true,{color:'red'},[13,45]];
for(var i=0;i<arr.length;i++){
console.log(arr[i]);
}
</script>
二、获取数据
获取一个比较复杂的数据时,首先要观察这个数据的类型,对象则用点语法,数组则用下标。如果要访问数组中多个元素,则用for循环遍历。以下是一个获取sina数据的示例。
<script src="./sina.js"></script>
<script>
console.log(sina);
for(var i =0;i<19;i++){
console.log(sina.statuses[i].text);
console.log(sina.statuses[i].user.name);
for(var j=0;j<sina.statuses[i].pic_urls.length;j++){
console.log(sina.statuses[i].pic_urls[j].thumbnail_pic);
}
}
</script>
首先获取到的变量sina是一个对象,对象访问使用点语法,然后获取到的属性是一个数组,访问使用下标,之后就又是对象,使用点语法,最后的到每一条微博的名字和内容。(数据量较大,运行结果只截取一部分)
三、函数设计
1、设计一个函数,实现的功能为返回一个数组中的最大数和最小数。
<script>
var arr = [29,32,45,23,543,234,13];
function max(n){
var max=-Infinity,min=Infinity;
for(var i=0;i<n.length;i++){
if(n[i]>max){
max=n[i]
}
if(n[i]<min){
min=n[i]
}
}
return '最大数:'+max+'\n'+'最小数:'+min;
}
var a=max(arr);
console.log(a)
</script>
2、设计一个函数,打印一个数的阶乘。
<script>
function fn(n){
for(var i=n-1;i>0;i--){
n*=i;
}
console.log('阶乘为'+n);
}
fn(4);
</script>
四、函数的参数
实参和形参。实参:为调用函数时实际传的参数。形参:声明函数时,括号中的变量为形参。
在调用函数时,有时候会发生传的参数比形参多了或是少了,会不会有影响呢,我们来验证以下。
<script>
function fn(x,y){
return x+y;
}
var re = fn(3,34,19);
console.log(re);
var re2 = fn(18);
console.log(re2);
</script>
从上述例子中可以看出,参数多了的情况下,首先是实参与形参一一对应进行赋值,当没有多的形参需要进行赋值时,多的那个实参则没有赋值给谁。而实参少的则是在给形参赋值时,有形参没有得到赋值,在变量的操作中了解到当一个变量声明后却没有赋值,类型是undefined,所以当一个number类型的数据和undefined类型的数据相加时,结果为NaN。
首先了解两个东西,一个是函数的length(写在函数外部),一个是arguments[](写在函数里面)。函数是一种引用数据类型,那它就是一种特殊的对象,就可以使用点语法,调用length,返回值是形参个数。arguments类型是数组,存储的是实参,点语法调用length返回的是实参个数。
把这个运用到上面的例子中就是多的隐式操作。调用时传的实参放在了arguments数组中,然后形参进行隐式声明,第一个形参要存的值为数组第一个元素的值,以此类推,当形参个数比实参多时,后面的的形参要去取数组中对应的值,实际上就是取数组中不存在的下标的值,则为undefined。
为解决undefined的情况,可以先给变量初始化,若之后取到实参的值则覆盖,没取到则为初始化时的默认值。初始化有以下三种方法。
五、函数的返回值
函数调用一定可以生成一个结果,结果可用可不用。有几种情况:没有执行return;执行了return,但后面没有跟表达式;有return,后面还有表达式,则把表达式的结果返回。前两种情况得到的都是return,最后一种根据表达式而定,且表达式可以是多种类型,比如原始表达式、对象及对象访问、函数调用、计算表达式。
<script>
function fn(age){
function fn2(){
if(age>=60){
return age+'可以退休了'
}else if(age>=22){
return age+'可以结婚了'
}
}
if(age>=18){
return fn2(age);
}else {
return age+'未成年';
}
}
var re2 = fn(25);
console.log(re2);
</script>
六、函数-变量的作用域
访问一个标识符时(标识符:变量或者函数),先访问当前作用域,没有就访问外层的作用域,直到全局作用域。下方的例子中c的值是a乘b的结果,但在fn2函数中并没有这两个变量,所以就往外找,找到b,再找到全局作用域中,找到a,最后得出结果。
<script>
var a =20;
function fn(){
var b =30
function fn2(){
var c = a*b;
console.log(c)
}
fn2();
}
fn(); //结果:打印a*b的结果,也就是600
</script>
提到作用域,就会想到全局变量和局部变量,放到JavaScript中,就是一个标识符,可能是全局标识符,可能是局部标识符。
<script>
var x = 13;
function fn(){
console.log(x);
var y = 27;
}
fn(); //打印13
console.log(y); //报错,提示y没有定义
</script>
<script>
function fn(x,y){
function fn2(n1){
return n1%2;
}
var re = x*y;
return fn2(re);
}
console.log(fn(3,5)); //打印1
console.log(fn2(12)); //报错,提示fn2没有定义
</script>
七、函数-执行过程
1、语法规则
函数调用一次就会运行一次,如果函数是在A作用域生成的,但在B作用域调用,则函数的代码运行在A作用域,也就是生成函数的作用域。
<script>
var a =57;
function fn(){
var a =38;
function fn2(){
console.log(a);
}
return fn2;
}
var re = fn();
re(); //打印结果38
</script>
上述示例中,在全局下定义了一个变量a,在函数内部也定义了一个变量a,函数fn返回的是fn2的函数体,将这个函数体赋给变量re,让re成为一个函数并进行调用,这时就会产生一个疑问,打印全局变量a的值57还是函数体中变量的值38。首先,re的这个函数是在fn函数的内部生成的,调用是在全局的作用域,按照上述结论便可知,re这个函数是运行在fn内部的,根据变量重复赋值,取值时取最后一次存的值得出,打印的是38。
2、参数和作用域
前面我们都是将参数和作用域分开来讲,现在就将它们结合起来进行分析。先看下方示例代码。
<script>
var a = 10;
function fn(a){
// 形 实 函 运
// var a; var a;
// var a =10;
// function a(){}
// 运行代码
console.log(a);
var a=25;
console.log(a);
function a(){}
console.log(a)
}
console.log(a);
fn(a);
console.log(a);
</script>
看到这个结果,可能没有理解是怎么来的,现在我们来分析以下。首先是一个口诀(在作用域生成时):形 实 函 运。
形:形参或者局部变量的声明;
实:实参赋值给形参变量;
函:内部的函数进行声明;
运:运行代码。
先进行第一步,将形参和局部变量进行声明,也就是注释中的“var a;”,然后是实参赋值给形参变量,a的值变为10,然后是函数的声明,最后运行代码。其实可能最难理解的是fn中第一个打印的是函数,这其实很好理解,首先是要打印a则要进行取值,取值取的是最后一次存的值,然后就要想到声明一个变量时可以是什么类型,其中也包括函数类型。变量a刚开始存的是number类型数据,最后一次存的值是函数类型数据,所以打印结果则是a这个函数。接着下一句又重新进行赋值,a的值改变,所以后面两次打印结果为25。