问:之前学习的变量,只能存储一个值。如果我们想存储班级中所有学生的姓名,那么该如何储存呢?
答:可以使用数组(Array)。数组可以把一组相关的数据一起存放,并且提供方便的访问(获取)方式
问:什么是数组呢?
答:数组是指一组数据的集合,其中的每个数据被称作元素,再数组中可以存放任意类型的元素。数组是一种将一组数据存储在单个变量名下的优雅方式
// 普通变量一次只能存储一个值
var num = 10;
// 数组一次可以存储多个值
var arr = [1,2,3,4,5];
数组(Array)就是一组数据的集合,存储在单个变量下的优雅方式
JS 中创建数组有两种方式:
var 变量名 = new Array();
创建了一个空数组
使用数组字面量方式创建空的数组
var 变量名 = [];
也是创建了一个空数组
数组里面的数据一定要用逗号分隔:
var arr1 = [1, 2, 'pink老师', true];
数组里面的元素比如说:1, 2 我们称为数组元素
数组中可以存放任意类型的数据,例如字符串,数字,布尔值等
var arrStus = ['小白',12,true,28.9];
控制台会输出全部4个数组:
var arr1 = [1, 2, 'pink老师', true];
console.log(arr1);
但是,在开发里面,需要获取数组里面的元素,请看下一级
索引也称下标,用来访问数组元素的序号(数组下表从0开始)
var arr = ['小白','小黑','大黄','瑞奇'];
索引号:0 1 2 3 依次排列
数组可以通过索引来访问、设置、修改对应的数组元素,我们可以通过“数组名[索引]”的形式来获取数组中的元素
这里的访问就是获取得到的意思
获取数组元素:格式 数组名[索引号];
var arr = ['小白','小黑','大黄','瑞奇'];
console.log(arr[2]);
结果:大黄
如果是 console.log(arr1[3]); 的话结果是:瑞奇
但是如果这样写的话:
var arr = ['小白','小黑','大黄','瑞奇'];
console.log(arr[4]);
结果:undefind
一定要记住:索引号从 0 开始
案例:数组练习
遍历:就是把数组中的每个元素从头到尾都访问一次(类似我们每天早上学生的点名)
var arr = ['red', 'green', 'blue'];
for (var i = 0; i < 3; i++) {
console.log(arr[i]);
}
因为数组索引号从 0 开始,所以 i 必须从 0 开始 i < 3 输出的时候 arr[i] i 计数器当索引号来用
遍历数组案例:
使用 "数组名.length" 可以访问数组元素的数量 (数组长度)
var arr = ['关羽', '张飞', '马超', '赵云', '黄忠', '刘备', '姜维'];
console.log(arr.length);
结果:7
也有更简单的写法:
var arr = ['关羽', '张飞', '马超', '赵云', '黄忠', '刘备', '姜维', '其他'];
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
结果:8
因为 arr.length 是动态检测数组元素的个数
遍历数组案例:
var arr = [2, 6, 1, 77, 52, 25, 7];
var max = arr[0];
for (var i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
console.log('该数组里面的最大值是:' + max);
要求:将数组 ['red','green','blue','pink'] 转换为字符串,并且用 | 或其他符号分隔
输出:'red|green|blue|pink|'
案例分析:
var arr = ['red', 'green', 'blue', 'pink'];
var str = '';
var sep = '|';
for (var i = 0; i < arr.length; i++) {
str += arr [i] + sep;
}
console.log(str);
实例:
实例:
var arr = ['red', 'green', 'blue'];
console.log(arr.length);
arr.length = 5;
但是第 3 4 个元素是 undefined
实例:
var arr1 = ['red', 'green', 'blue'];
arr1[3] = 'pink';
console.log(arr1);
这是一种比较常用的方法,叫做 "追加数组元素"
可以替换原先数组里面的元素:
var arr2 = ['red', 'green', 'blue'];
arr2[0] = 'yellow';
console.log(arr2);
结果:['yellow', 'green', 'blue'];
注意:不要直接给数组名赋值,否则里面的数组元素都没有了
新建一个数组,里面存放10个整数 (1~10`)
var arr = [];
for (var i = 0; i < 10; i++) {
arr[i] = i + 1;
}
console.log(arr);
实例:
要求:将数组 [2, 0, 6, 1, 77, 0, 52, 0, 25, 7] 中大于等于10的元素选出来,放入新数组。
方法一:
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
var j = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] > 10) {
newArr[j] = arr[i];
j++;
}
}
console.log(newArr);
方法二:
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] >= 10) {
newArr[newArr.length] = arr[i];
}
}
console.log(newArr);
案例:
案例:
懂了吗?懂了的话你会说一声: "妙~~啊~~~"
其他案例:
函数在使用时分为两步:声明函数和调用函数。
语法结构:
function 函数名() {
//函数体
}
以下就是最简单的函数
function sayHi() {
console.log('Hi~~');
}
function 是声明函数的关键字,注意全部小写
函数是做某件事情,函数名一般是动词 sayHi
函数不调用自己不执行
调用函数名来执行函数体代码
function 函数名() {
//函数体
}
函数名();
注意: 一定不要忘了加小括号
1.声明函数
function getSum() {
var sum = 0;
for (var i = 1; i <= 100; i++) {
sum += i;
}
console.log(sum);
}
2.调用函数
getSum();
案例:
在声明函数时,可以在函数名称后面的小括号中添加一些参数,这些参数被称为形参,而在调用函数时,同样也需要传递相应的参数,这些参数被称为实参
| 参数 | 说明 |
|---|---|
| 形参 | 形式上的参数 函数定义的时候 传递的参数 当前并不知道是什么 |
| 实参 | 实际上的参数 函数调用的时候传递的参数 实参时传递给形参的 |
我们可以利用函数的参数实现函数重复不同的代码
function 函数名(形参1, 形参2...) {
}
在声明函数的小括号里面是形参(形式上的参数)
参数名(实参,实参2...);
在函数调用的小括号里面是实参(实际的参数)
形参和实参的执行过程
function cook(aru) {
console.log(aru);
}
cook('酸辣土豆丝');
结果:'酸辣土豆丝'
形参是接受实参的 aru = '酸辣土豆丝' 形参类似于一个变量
function cook(aru) {
console.log(aru);
}
cook('酸辣土豆丝');
cook('大肘子');
结果:输出一个 '酸辣土豆丝' 再输出一个 '大肘子'
这就等于执行了两遍
提示:函数的参数可以有也可以没有,个数不限
利用函数求任意两个数的和
function getSum(num1, num2) {
console.log(num1 + num2);
}
getSum(1, 3);
利用函数求任意两个数之间的和
function getSums(start, end) {
var sum = 0;
for (var i = start; i <= end; i++) {
sum += i;
}
console.log(sum);
}
getSums(1, 100);
案例:
| 参数个数 | 说明 |
|---|---|
| 实参个数等于形参个数 | 输出正确结果 |
| 实参个数多于形参个数 | 只取到形参个数 |
| 实参个数小于形参个数 | 多的形参定义为 undefined 结果为 NaN |
有时候,我们会希望函数将值返回给调用者,此视通过使用 return 语句就可以实现
function 函数名() {
return 需要返回的结果;
}
函数名();
我们函数只是实现某种功能,最终的结果需要返回给函数调用者函数名() 通过 return 实现的
只要函数遇到 return 就把后面的结果返回给函数的调用者 函数名() = return 后面的结果
代码验证:
function getResult() {
return 666;
}
getResult();
console.log(getResult());
求两个数的和
function getSum(num1, num2) {
return num1 + num2;
}
console.log(getSum(1, 2));
这样做才算一个完美意义上的写法
利用函数求任意两个数的最大值
function getMax(num1, num2) {
if (num1 > num2) {
return num1;
} else {
return num2;
}
}
console.log(getMax(1, 3));
结果:3
也可以这样写:
function getMax(num1, num2) {
return num1 > num2 ? num1 : num2;
}
console.log(getMax(1, 3));
利用函数求任意一个数组中的最大值
求数组 [5, 2, 99, 101, 67, 77] 中最大数值
function getArrMax(arr) {
var max = arr[0];
for(var i = 1; i <= arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
var re = getArrMax([5, 2, 99, 101, 67, 77]);
console.log(re);
在实际开发里面,我们经常用一个变量来接收函数的返回结果使用更简单
return 语句之后的代码不被执行
function getSum(num, num2) {
return num1 + num2;
alert('我是不会被执行的哦!');
}
console.log(getSum(1, 2));
结果:3
return 后面的代码不会被执行
return 只能返回一个值
function fn(num1, num2) {
return num1, num2;
}
console.log(fn(1, 2));
结果:2
它返回的结果是最后一个值
我们求任意两个数的加减乘数结果
function getResult(num1, num2) {
return [num1 + num2, num1 - num2, num1 * num2, num1 / num2];
}
var re = getResult(1, 2);
console.log(re);
当我们不确定多少个参数传递的适合,可以用 arguments 来获取。在 JavaScript 中 arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中储存了传递的所有实参。
arguments 的使用
function fn() {
console.log(arguments);
}
fn(1, 2, 3);
结果:[1, 2, 3];
arguments 可以存储数据,用户输入几个就存储几个
我们可以按照数组的方式遍历 arguments
function fn() {
for (var i = 0; i < arguments.length; i++) {
console.log(arguments[i]);
}
}
当你也不知道用户需要储存多少个数值的时候,arguments 就有用了,它可以存储一个或多个数值
代码:
function getMax() {
var max = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
}
console.log(getMax(1, 2, 3));
console.log(getMax(1, 2, 3, 4, 5));
console.log(getMax(11, 2, 34, 444, 5, 100));
结果:3 5 444
这样就可以利用 arguments 求任意数值的最大值。实例:
代码:
function reverse(arr) {
var newArr = [];
for (var i = arr.length - 1; i >= 0; i--) {
newArr[newArr.length] = arr[i];
}
return newArr;
}
var arr1 = reverse([1, 3, 4, 6, 9]);
console.log(arr1);
var arr2 = reverse(['red', 'pink', 'blue']);
console.log(arr2);
实例:
代码:
function sort(arr) {
for (var i = 0; i < arr.length - 1; i++) {
for (var j = 0; j < arr.length - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
var temp =
arr[j];
arr[j] = arr[j +
1];
arr[j + 1] =
temp;
}
}
}
return arr;
}
var arr1 = sort([1, 4, 2, 9]);
console.log(arr1);
实例:
代码:
function isRunYear(year) {
var flag = false;
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
flag = true
}
return flag;
}
console.log(isRunYear(2000));
如果结果是 true 就是闰年
实例:
fn1 和 fn2 互相调用
function fn1() {
console.log(11);
fn2();
}
fn1();
function fn2() {
console.log(22);
}
利用函数相互调用组成代码
// 用户输入年份,输出当前年份2月份的天数
function backDay() {
var year = prompt('请您输入年份:');
if (isRunYear(year)) { // 调用函数需要加小括号
alert('当前年份是闰年2月份有29天');
} else {
alert('当前年份是平年2月份有28天');
}
}
backDay();
// 判断是否为闰年的函数
function isRunYear(year) {
// 如果是闰年我们返回 true 否则 返回 false
var flag = false;
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
flag = true;
}
return flag;
}
实例:
利用函数关键字自定义函数(命名函数)
function fn() {
}
fn();
函数表达式(匿名函数)
var fun = function(aru) {
console.log('我是函数表达式');
console.log(aru);
}
fun('pink老师');
fun是变量名 不是函数名
函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而 函数表达式里面存的是函数
函数表达式也可以进行传递参数
JavaScript 作用域就是代码名字在某个范围内起作用和效果,目的是为了提高程序的可靠性更重要的是减少命名冲突
全局作用域就是整个 script 标签,或者是一个单独的 JS 文件
比如说一个页面的一段 JS 代码,就是全局作用域
var num = 10;
局部作用域(也叫函数作用域)在函数内部就是局部作用域,这个代码的名字只在函数内部起效果和作用
局部作用域就是在函数里面的作用域:
function fn() {
// 局部作用域
var num = 20;
console.log(num);
}
fn();
全局作用域和局部作用域不会互相影响
根据作用域的不同我们变量分为全局变量和局部变量
num 就是一个全局变量
var num = 10;
console.log(num);
全局变量可以在函数中使用
var num = 10;
function fn() {
console.log(num);
}
fn();
以上结果为:10
局部变量就是在局部作用域下的变量,后者在函数内部的变量就是局部变量
function fun() {
var num1 = 10;
}
console.log(num1);
结果:Uncaught ReferenceError: num1 is not defind
事实证明,局部作用域是不能在全局作用域中使用的
注意:如果在函数内部没有声明直接赋值的变量也属于全局变量
function fun() {
num2 = 20
}
console.log(num2);
结果:20
函数的形参也可以看作是局部变量
从执行效率来看全局变量和局部变量:
JavaScript 的作用域:全局作用域、局部作用域、现阶段我们 JS 没有块级作用域
我们 JS 也是在 es6 的时候新增的块级作用域
块级作用域 {} | if {} | for {}
使用花括号的写的变量都可以使用
if (3 < 5) {
var num = 10;
}
console.log(num);
作用域链:内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值,这种结构我们称为作用域链,就近原则
var num = 10;
function fn() { // 外部函数
var num = 20;
function fun() { // 内部函数
console.log(num);
}
fun();
}
fn();
结果是:20
这个内部函数会首先检查自己内部的函数,如果没有,返回上一级函数查找变量,如果还是没有,返回最上面查找变量,如果还没有,那就报错了
案例1:结果是几
function f1() {
var num = 123;
function f2() {
console.log(num);
}
f2();
}
var num = 456;
f1();
结果是:123
案例2:结果是几
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2 {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a);
console.log(b);
}
}
}
fn1();
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
我们 JS 引擎分为两步:预解析、代码执行
预解析就是 JS 引擎把 JS 里面所有的 var 还有 function 提升到当前作用域的最前面,然后进行代码执行,按照代码书写的顺序从上往下执行
预解析发呢为变量预解析(变量提升)和函数预解析(函数提升)
(1) 变量提升就是把所有的变量声明提升到当前的作用域最前面,不提升赋值操作
console.log(num);
var num = 10;
结果:undefind
此代码就相当于执行了这个代码:
var num;
console.log(num);
num = 10;
num 被提升到前面去了
那么为什么这行代码会报错呢?
fun();
var fun = function() {
console.log(22);
}
结果:报错
因为这行代码就相当于执行了以下代码:
var fun;
fun();
fun = function() {
console.log(22);
}
因为没有那个函数所以报错了
正确写法:
fun = function() {
console.log(22);
}
fun();
(2) 函数提升就是把所有函数声明提升到当前作用域的最前面,不调用函数
fn();
function fn() {
console.log(11);
}
结果是:11
这就是函数提升
如果是直接赋值的形式:"var fun = function()" 就不支持提升
案例1:
var num = 10;
fun();
function fun() {
console.log(num);
var num = 20;
}
结果是:20
相当于执行以下操作:
var num;
function fun() {
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
结果是:undefined
案例2:
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fn()
相当于执行以下代码:
var num;
function fn() {
var num;
console.log(num);
num = 20;
console.log(num);
}
num = 10;
fn();
结果是:undefined 和 20
案例3:
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
结果:9 9 9 9 9 报错