Web前端_JavaScriptDay10_函数


前言

    无论是什么程序设计语言,函数都是重要的一部分内容,在实际开发过程中有很多语法的表达和功能的实现都来源于函数。不过与其它语言不同的是,JavaScript是通过函数来实现面向对象的特性并非通过专门的面向对象语法去实现的,因为JavaScript没有属于自己的专门的面向对象语法,所以函数在JavaScript中更是重中之重。


一、函数的介绍

1.什么是函数?

    函数是执行特定任务的代码块,之后通过调用函数实现特定任务功能的实现。

2.函数的组成部分

  • 关键字function。
  • 函数名称。
  • 函数所需要的参数,参数可以是0个,也可以是多个,参数之间要用逗号分隔。
  • 函数执行的代码块,即函数体。
  • 返回值语句return,函数通常都会有返回值,如果某个函数没有显式的返回值,默认返回值为undefined。
function sum(number1,number2) {
    var sum = number1 + number2;
    return sum;
}

3.如何去调用函数?

​     在明白了函数的组成部分后,我们就可以成功创建函数了。不过这只是第一步,在我们创建函数之后要想去使用函数还需去调用函数,因为函数不调用的话是不会执行的。

​     调用函数的方法是在函数名加传递参数的括号即可。

function sum(number1,number2) {
    var sum = number1 + number2;
    return sum;
}
var result = sum(5,4);
console.log(result);		//9

4.关于函数中的参数

    定义函数的时候我们可能会设置函数所需要的调用参数,这个参数的设定不是必须的,可以选择不设定。如果设定了调用参数,在调用函数的时候就必须要传递相关的参数值,程序才能正常执行。如果没有传递相关的参数值,未被传递参数值的地方就会默认为undefined。

//函数中设置了调用参数但是在调用函数的过程中并未去传递相关参数值导致的结果。
function sum1(number) {
    return number;
}
var result1 = sum1();
console.log(result1);	//undefined

//函数中漏传参数导致参数+undefined得到NaN。
function sum2(number1,number2) {
     return number1 + number2;
}
var result2 = sum2(1);
console.log(result2);	//NaN

    参数分为形式参数实际参数两种,其中形式参数是指定义函数时所用到的参数,实际参数是指在调用函数时所传递的参数。

function sum(number1,number2) {
    var sum = number1 + number2;
    return sum;
}
var result = sum(5,4,3,2,1);	//JavaScript只会解析5和4这两个值,最后输出结果9,其它会被忽略
console.log(result);

    不过我们可以使用arguments变量在函数中去调用并返回接受的所有参数,arguments变量是内建变量,在每个函数中都能调用。

function args() {
    return arguments;
}
var result = args(5,4,3,2,1,true,"A",'b');
//Arguments(8) [5, 4, 3, 2, 1, true, "A", "b", callee: ƒ,Symbol(Symbol.iterator): ƒ]
console.log(result);

    通过arguments可以对参数进行求和运算。

function sum() {
    var result = 0;
    for(var i = 0 ; i < arguments.length ; i++) {
        result += arguments[i];
    }
    return result;
}
var res = sum(5,4,3,2,1);
console.log(res);			//15

二、parseInt()

    parseInt()会将接收到任何输入值转换为整数类型输出,通常都是输入字符串,转换失败则返回NaN。

var a = parseInt("5a7b6");
console.log(a);			//5
var b = parseInt("1024");
console.log(b);			//1024
var c = parseInt("abc1024");
console.log(c);			//NaN
var d = parseInt("3.14");
console.log(d);			//3
var e = parseInt("0124");
console.log(e);			//124
var f = parseInt("0x1024");
console.log(f);			//4132

    parseInt(string,radix)中可以传两个值,第一个值可以解析的是字符串,第二个值解析的是数字的基数,即设定函数所要被解析的数据类型,其中可以传递的进制值范围在2~36之间,如果以"0x"开头第二参数则默认指定为16进制数。

var a = parseInt("0x1024");
console.log(a);			//4132

    注意:在这个函数的应用过程中我们会发现一个很有趣的现象,如果以“0x”开头的数字第二参数默认指定为16进制数,那么按道理以“0”开头的数字第二参数应该会被默认指定为8进制数,但是在现实中并不是这样的。如果我们使用parseInt()函数反而得不到这个结果,以“0”开头的数字最终会忽略0而被解析0后面的数字为10进制的数值。因为ECMAScript5移除了8进制的默认表示法,这种做法是避免了在8进制解析和10进制解析时候的混淆。

var a = parseInt("0124");
console.log(a);			//124

三、parseFloat()

    上面我们学习了parseInt()的使用,parseFloat()的使用与parseInt()是基本相同的,区别在于parseFloat()只能将输入值转换为十进制数,所以这个函数只能传入一个参数。而且parseFloat()解析的字符串返回的是一个浮点数。

var a = parseFloat("3.14a");
console.log(a);			//3.14
var b = parseFloat("3.14");
console.log(b);			//3.14
var c = parseFloat("1.230800");
console.log(c);			//1.2308
var d = parseFloat("ab12c");
console.log(d);			//NaN

    parseFloat()可以接受指数形式的数据。

var a = parseFloat("123e-2");
console.log(a);			//1.23
var b = parseFloat("1e5");
console.log(b);			//100000

四、isNaN()

    使用isNaN()函数可用于检查参数是否是非数字值。

console.log(isNaN(1024));			//false
console.log(isNaN(-1024));			//false
console.log(isNaN(1.024));			//false
console.log(isNaN(-1.024));			//false
console.log(isNaN(2024-2));			//false
console.log(isNaN(0));				//false
console.log(isNaN("JavaScript"));	//true
console.log(isNaN("2021/01/01"));	//true

    使用isNaN()函数可以检测parseInt()和parseFloat()是否成功调用。

var a = isNaN(parseInt("0x1024"));
console.log(a);		//false
var b = isNaN(parseFloat("1.1"));
console.log(b);		//false
var c = isNaN(parseInt("1.2"));
console.log(c);		//false
var d = isNaN(parseInt("ac1024"));
console.log(d);		//true
var e = isNaN(parseFloat("ac1024"));
console.log(e);		//true

    值得一提的是,NaN自己不存在等值的概念,所以NaN == NaN返回的是false。

五、isFinite()

    isFinite()可以检查输入的是否是一个非Infifnity非NaN的数字。

console.log(isFinite(Infinity));	//false
console.log(isFinite(-Infinity));	//false
console.log(isFinite(1024));		//true
console.log(isFinite(1e308));		//true
console.log(isFinite(-1e308));		//true
console.log(isFinite(1e309));		//false
console.log(isFinite(-1e309));		//false

六、eval()

    eval()函数会将输入的字符串当做JavaScript代码执行。

eval('var a = 1;');
console.log(a);			//1

七、变量的作用域

    在JavaScript中,变量的作用域是以函数作为作用域的,即变量如果是在某个函数定义的,该变量在函数以外的地方是不可见的。如果该变量是定义在if或者for这样的代码块中,它在代码块之外是可见的。定义在所有函数之外的变量是全局变量,定义在函数中的变量是局部变量。

var number1 = 1;
function f() {
    var number2 = 4;
    number1++;
    console.log(number2);   //4
    return number1;
}
console.log(number1);   //1
var result = f();
console.log(result);    //2
console.log(number2);   //Uncaught ReferenceError: number2 is not defined

    由以上示例可以看出函数f()可以访问number1,number1是全局变量,而在函数体外number2无法被访问,因为number2是局部变量,局部变量只能在本函数中被访问。
    但是,在JavaScript中总有一些令人比较惊讶的现象。如果在声明变量的时候没有去使用关键字变量去定义相关变量的话,该变量会被默认为全局变量。

var number1 = 1;
function f() {
    number2 = 2;
}
f();
console.log(number2);		//2

八、匿名函数

    没有名字的函数被称为匿名函数。

var a = function() {
    return 2;
}
var b = function(x) {
    return x;
}

    形如以上的示例就是匿名函数。当匿名函数不被赋值给变量去单独使用的时候,这类函数有两种用法:

  • 可以将匿名函数作为参数传递给其它函数,这样接收方函数可以利用传递的函数完成某些事情。
  • 可以去定义某个匿名函数执行某些一次性任务。
    在后面的内容中我们会用到这些用法。

九、回调函数

1.回调函数与匿名回调函数

    函数A传递给函数B,函数B来执行函数A的时候,A就是一个回调函数。

function sum(a) {
    return a();
}
var result = sum( 
	function() {
    	return 1;
	}
	);  
	console.log(result);	//1

    也可以使用回调函数进行进行加法运算。

function sum(a,b,c) {
    return a() + b() + c();
}
var result = sum(
    
	function() {
    	return 1;
	},
	function() {
    	return 2.5;
	},
	function() {
    	return 3;
	}
	);  
	console.log(result);	//6.5

    我们看到这两个示例中在调用sum的时候都是使用了匿名函数,而且这些匿名函数也是一个回调函数,这样的函数我们称之为匿名回调函数。

2.什么情况下使用回调函数?

  • 在未命名的情况下去传递函数,从而节省变量名的使用。
  • 将一个函数调用给另一个函数去执行,可以节省一些代码编写工作。
  • 在数据量很大的情况下使用回调函数是一个好的选择。
function sum(a,b,c,returnValue) {
    var array = [];
    for(var i = 0;i < 3;i++) {
        array[i] = returnValue(arguments[i] * 2);
    }
    return array;
}

var result = sum(1,2,3,function(a) {
    return a + 1;
});

console.log(result);		//[3, 5, 7]

十、即时函数

    可以在被定义后立即调用的函数是即时函数。

(
	function() {
        console.log('JavaScript');	//JavaScript
    }
)();

    括号也可以放在第二对括号之后。

(
	function(message) {
        console.log('Hello ' + message);		//Hello JavaScript
    }
('JavaScript'));

    使用匿名函数的好处是不会产生任何全局变量。缺点是在于这样的函数是无法重复执行的,这也使即时函数非常适合于去执行一些一次性的或初始化的任务。

十一、内部函数

1.什么是内部函数?

    在一个函数内部定义另一个函数,内部定义的函数就被称为内部函数,内部函数也叫做私有函数,只能在内部去访问。

function outer(param) {
    
    function inner(theinput) {
        return theinput * 2;
    }
      	return 'The result is ' + inner(param);
}

console.log(outer(2));		//The result is 4

2.私有函数的特点

  • 确保全局名字空间的唯一性,以免命名冲突。
  • 确保一些函数的私有性,做到只将一部分必要的函数暴露在外,具有一定的安全性。

十二、返回函数的函数

    返回函数的函数听起来有些奇怪,不过细细想一想的话就是在一个函数中的返回值也是一个函数,这就是返回函数的函数。

function a() {
    console.log("Hello");
    return function() {
        console.log("JavaScript");
    }
}
var result = a();	//Hello
result();	//JavaScript

//也可以这样去输出,结果是相同的
//a()();	//Hello
			//JavaScript

十三、函数可以被重写

    还是上面的例子,我们可以使用新的函数去覆盖旧的函数,我们在函数内部去重写函数覆盖外部的函数。

function a() {
    alert("Hello");
    b = function() {
        alert("JavaScript");
    }
}
a();	//Hello
b();	//JavaScript

十四、闭包

    在看闭包之前先看一个示例:

function sum(number) {
    var all = 0;
    return all += number;
}

console.log(sum(1));	//1
console.log(sum(1));	//1
console.log(sum(1));	//1
console.log(sum(1));	//1
console.log(sum(2));	//2
console.log(sum(2));	//2
console.log(sum(3));	//3

    上面的示例中我们如果不改变传入函数的数值无论是调用多少次最终的结果就不会被改变,在某些应用场景下这是极其不方便的,这时候就引入了闭包。在使用闭包的时候,我们可以在反复调用的过程中去不停的进行值的改变。在实际中我们可以以日常多开网站去举例。
    我们日常可能会多开好几个网站,每个网站我们可能会在同一个浏览器上打开好几个,在我们打开同一个浏览器好几个页面的时候会占用内存空间,几个页面运行的过程中可以看做是反复调用函数,这个过程中我们在同一个浏览器去打开多个页面的时候每次打开的页面都和我们上次打开的页面不同,这个过程细化过来我们可以将其看做是闭包,是调用函数且还占用内存去执行并变化的过程,变量会一直保留在内存中,所以我们在最小化浏览器页面后浏览器并未被关闭,内存依然会被占用。

function sum(number) {
    var all = 0;
    return function() {
        all += 1;
        return all;
    }
}

var storage = sum();
console.log(storage());	//1
console.log(storage());	//2
console.log(storage());	//3
console.log(storage());	//4

    从上面的示例可以明白闭包是创建一个函数,用一些变量包装起来,之后再保存起来去使用,而函数保留对其作用域访问的过程我们就称之为闭包。
    当然,每次在定义函数的时候都会为函数创建闭包,所以我们可以说每个函数都有闭包。但是,只有我们在使用嵌套函数的时候闭包的功能才能真正发挥出来。

var number = 1;
function sum1() {
    var number = 4;		//覆盖了上面的number
    
    function sum2() {
        console.log("这个数字为:" + number);		//sum2()函数和其中的语法形成了一个闭包,引用的sum1()中局部声明的number变量。
    }
    return sum2();
}
sum1();		//这个数字为:4
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值