函数
函数是一组语句的集合,它是一个独立运行的程序单元。本质上,它是一段子程序,函数是JavaScript的核心。每一个函数都有一个函数体,它是构成该函数的一组语句集合。函数声明完后需要调用(也称为运行、执行、请求或者调度)才会去执行函数体。
函数的定义
第一种定义方式:函数声明
function 函数名(){
函数体
}
第二种定义方式:函数表达式
var 变量 = function(){
函数体
}
注意: 第二种方式的本质 其实是定义了一个变量,并将这个函数的地址交给该变量。于是,函数名就是这个变量名。
函数的调用
函数调用方式:
函数名();
-
函数声明定义出来的函数
既可以在函数定义之前使用(但是建议不要这样用)
也可以在函数定义之后使用 -
函数表达式定义的函数
只能够在函数定义之后使用
区分函数的引用、调用
- 调用:当在函数名后面添加圆括号时,JavaScript就知道要调用它,然后执行函数体,最后返回结果;
- 引用:函数名后面没有圆括号时,仅仅是在引用这个函数,并没有调用它。
函数的特殊调用(IIFE)
IIFE:立即调用的函数表达式,声明函数的同时立即调用这个函数。
IIFE的常用写法:这两种写法的作用相同,只是表现形式不同而已,()只是起了自执行的作用
- (function(){…})() 把函数当作表达式解析,然后执行解析后的函数[相当于 var a = function(){}; a(); a得到的是函数]
- (function(){…}())是把函数表达式和执行当作语句直接执行[相当于 var a = function(){}(); a得到的是结果]
传统写法:
声明:function func(){…}
调用:func();
IIFE和传统写法的区别:
IIFE:是用一个()把函数声明括起来了,让js编译器知道,这是一个需要立即执行的函数;
传统:声明函数之后,只有在调用的时候才会执行函数,并且直接污染全局命名空间。
说明: 所谓不去污染全局命名空间,是因为 IIFE 创建了一个新的函数作用域,你真正的业务代码被封装在其中,自然就不会触碰到全局对象了。如果你需要全局对象,那就 pass 给 IIFE:
void function (global) {
// 在这里,global 就是全局对象了
}(this) // 在浏览器里,this 就是 window 对象
为什么要使用IIFE:
在js中只有function才能实现作用域的隔离,如果要将一段代码中的变量、函数等的定义隔离出来,只能将这段代码封装到一个函数中。
在我们通常的理解中,将代码封装到函数中的目的是为了复用,在JS中,当然声明函数的目的在大多数情况下也是为了复用,但是JS迫于作用域控制手段的贫乏,我们也经常看到只使用一次的函数:这通常的目的是为了隔离作用域,既然只使用一次,那么立即执行好了,既然只使用一次,函数的名字也省掉了,这就是IIFE的由来。
函数的参数
函数整体由关键字function
、函数名
、形参列表
、函数体
组成。形参列表中,可以放置 形式参数
。简称: 形参
。
// 定义一个函数,计算两个数字的和
function sum(num1, num2) {
// 形参num1 "代表" 将来函数执行的时候,要传递的一个参数
// 形参num2 "代表" 将来函数执行的时候,要传递的另一个参数
console.log(num1 + num2);
}
// 函数执行了
sum(1, 2); // 输出3
当函数执行的时候,可以往圆括号内填写数据,这种行为,叫做 传参
, 用于函数运行中使用,这样的参数叫做 实际参数
,简称 实参
。
- 函数定义时写的参数叫做形式参数,简称形参
- 调用函数时传递的参数叫做实际参数,简称实参
举例: 就像洗碗机一样,我们有了洗碗机(函数), 还需要把碗
放进去(传递参数),还需要把洗洁精
放进去(传递参数),这样,按下开关(调用函数)时,才可以最终得到一个干净的碗(返回值)。那么这里的碗
和洗洁精
等内容,就是实际参数
。而洗碗机放碗的位置,和放洗洁精的位置,就是形式参数
。
函数的参数关系
当函数定义时,可以定义形参,当函数执行时,可以传递实参。如果函数在执行时,传递的参数与形参不一致时,会发生什么呢?
- 当形参比实参多:多余的形参的值为undefined
function sum(a, b) {
console.log(a);
console.log(b);
}
sum(10); // a是10,b是undefined
function sum2(a,b,c){
console.log(a+b+c);
}
sum2(1,2); // NaN
- 当形参比实参少: 没有形参接收多余的实参
function sum(a, b) {
console.log(a);
console.log(b);
}
sum(10, 11, 12); // a是10,b是11,12没有形参来接收
function sum(a,b,c){
console.log(a+b+c);
}
sum(1,2,3,4); // 6
arguments
arguments是函数内部的一个成员,只有在函数执行的时候才会存在。可以使用它来获取本次函数在执行时,所有传递的实参。
arguments.length可以获取实参的个数。
function fun(){
console.log(arguments);
}
fun(1,2,3,4,5); // [1,2,3,4,5]
fun("a","b","c"); // ["a","b","c"]
arguments是一个类数组对象,也叫做伪数组对象。可以使用 arguments[idx]
来获取对应的值。 idx
是 从0
开始的。 这个idx
,也可以叫做 下标
或者 索引
function sum() {
console.log(arguments[2]);
}
sum(1, 2, 3, 4); // => 3
sum(1, 2); // => undefined
function demo(){
var sum = 0;
for (var i = 0; i <arguments.length; i++){
sum += arguments[i];
}
// 返回sum
return sum;
}
var num1 = demo(1, 2, 3, 4, 5, 6)
var num2 = demo(111, 2, 3)
console.log(num1); // 21
console.log(num2); // 116
return关键字
作用: 该关键字是用于在函数内部 返回内容
并 中止函数执行
的。
// 中止函数执行
function demo() {
console.log(1);
console.log(2);
console.log(3);
return;
console.log(4);
console.log(5);
}
demo(); // 只会输出1 2 3 而不会输出4 5 因为遇见了return
// 返回内容
var a = 10;
var b = 11;
function sum(num1, num2) {
return num1 + num2;
}
// 进行计算
var result = sum(a, b);
// 使用结果
console.log(result); // 21
function sum1(a,b){
a+b;
}
var num = sum1(1,2);
console.log(num); // undefined
注意:return
关键字只能够在函数内部出现。return在函数内只能使用一次。如果在函数体里面没有使用return返回结果,函数外面将接收不到结果,结果为undefined。
函数的定义过程
- 在内存中开辟一个空间
- 把代码放进去
- 把空间的地址交给函数名或者变量名来保存
函数的调用过程
- 根据函数名称找到内存空间
- 将实参的值传递给形参
- 开始解析内存空间中的代码
- 执行代码
函数的属性
name
它是函数的名称,函数的名称不论是表达式还是声明,都是变量的名字length
它是函数的形参的个数
function demo(a, b, c) {
}
console.log(demo.name); // "demo"
console.log(demo.length); // 3
var fun = function() {
}
console.log(fun.name); // "fun"
console.log(fun.length); // 0
求1+2!+3!+…+20!的值
方式1:
function jc(num){
var sum = 1;
for (var i = 1; i <= num; i++){
sum *= i
}
return sum;
}
var sum = 0;
for (var i = 1; i <= 20; i++){
console.log(jc(i));
sum += jc(i);
}
console.log(sum);
方式2:
function jc(m){
var sum = 0;
for(var i = 1; i <= m; i++){
for(var j = 1 , n = 1; j <= i ; j++){
n *= j;
}
sum += n;
}
document.write(sum);
}
jc(20);
加粗样式
function f(){
for (var i = 100; i < 1000; i++){
// 获取百位
var b = parseInt(i / 100);
// 获取十位
var s = parseInt(i / 10) % 10;
// 获取个位
var g = i % 10;
// 判定
if (b === s && b === g && s ===g){
console.log(i);
break; // 找到一个就退出循环不再继续寻找
}
}
}
f();
求水仙花:求一个三位数,他们的个、十、百位数的立方和等于该三位数
function f(){
for (var i = 100; i < 1000; i++){
// 获取百位
var b = parseInt(i / 100);
// 获取十位
var s = parseInt(i / 10) % 10;
// 获取个位
var g = i % 10;
// 判定
if (b*b*b + s*s*s + g*g*g === i){
console.log(i); // 153
break;
}
}
}
f();
定义一个函数,求任意3个数字的和
function sum(num1,num2,num3){
var sum = num1+num2+num3;
console.log("和为:" + sum); // 6
}
sum(1,2,3);
定义一个函数,求任意个数字的和
function sum(){
var sum = 0;
for(var i = 0; i < arguments.length; i++){
sum += arguments[i];
}
console.log(sum);
}
sum(1,2,10); // 13
sum(2,4,4,6); // 16
编写一个函数,计算任意两个数字之间所能组成的奇数个数,数字必须是个位数
比如: 计算0-3之间能组成的奇数个是01、03、11、13、21、23、31、33
方式1:
var m = +prompt("请输入0~9的数字","");
var n = +prompt("请输入0~9的数字","");
function num(m,n){
if(m >= 10 ||n >= 10){//如果m,n大于10 ,直接返回
alert("输入的值不在0~9的范围内!");
return;
}
if(m > n){//如果m大于n,调换m,n的位置
var temp = m;
m = n;
n = temp;
}
//for循环生成i,j之间的所有值
for(var i = m;i <= n;i++){
for(var j = m;j <= n;j++){
if(j%2!=0){//j不为偶数满足条件输出
console.log(""+i+j);//打印i,j的字符串输出
}
}
}
}
num(m,n);
方式2:
function num(a,b){
if(1 >= 10 || b >= 10){//如果m,n大于10 ,直接返回
alert("输入的值不在0~9的范围内!");
return;
}
// 判断a和b大小
if (a > b){
// 如果a>b,那么将两个变量值互换
var temp = a;
a = b;
b = temp;
}
// 代码执行到该行时,一定是a<b
for (var i = a; i <= b; i++){
// console.log(i);
for (var j = a; j <= b; j++){
if(j % 2 === 1){
console.log("" + i + j);
}
}
}
}
num(0,11);