JavaScript 函数
2.1 初始函数
- 在 JavaScript 中,函数类似于 Java 中的方法,是执行特定功能的 JavaScript 代码。
- 但是 JavaScript 中的函数使用更简单,不用定义函数属于哪个类,因此调用时不需要用"对象.函数名()"的方式。
- 直接使用函数名称来调用函数即可。
JavaScript 中有函数有两种:一种时 JavaScript 自带的系统函数,另一种时用户自行创建的自定义函数。
2.1.1 系统函数
- 在 JavaScript 中, 常用的系统函数有三种,分别是 parseInt()、parseFloat() 和 isNaN()。
- 其中前两种函数时用于将非数字的原始值转换成数字的函数.
- 最后一种系统函数是用于检查是否是非数字的函数。
1.parseInt()
- parseInt() 函数可以解析一个字符串,并返回一个整数,
- 语法
parseInt("字符串");
- 在判断字符串是否为数字前,paseInt() 和 paseFloat() 都会分析该字符串。
- parseInt() 函数首先查看下标为 0 的字符,判断它是否为一个有效数字。如果不是,则返回 NaN,不在继续执行其他操作。
var num1=parseInt("56.64"); //返回值为56
var num1=parseInt("123abc"); //返回值为123
var num1=parseInt("hello999"); //返回值为NaN
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
var num1=prompt("请输入第一个数");
var num2=prompt("请输入第二个数");
var parInt1=parseInt(num1);
var parInt2=parseInt(num2);
var result=parInt1+parInt2;
document.write("两个数相加之和为:"+result);
</script>
</body>
</html>
2.parseFloat()
- parseFloat() 函数可以解析一个字符串,并返回一个浮点数,
- 语法
parseFloat("字符串");
- parseFloat() 函数与 parseInt() 函数的处理方式相似,从下标 0 开始查看每个字符,直到找到第一个非有效的字符为止,然后把该字符之前的字符串转换为浮点数。
- 对于 parseFloat() 函数来说,第一个出现的小数点是有效字符,如果有两个小数点,那么第二个小数点被看做无效。
var num1=parseFloat("3.1415926"); //返回值为 3.1415926
var num1=parseFloat("123abc"); //返回值为 123
var num1=parseFloat("hello999"); //返回值为 NaN
var num1=parseFloat("52.18.97"); //返回值为 52.18
3.isNaN()
- isNaN() 函数用于检查其参数是否是非数字,
- 语法
isNaN(x);
- 如果 x 是特殊的非数字,则返回 true;否则返回 false。
var num1=isNaN("20.5"); //返回值为 false
var num1=isNaN("123abc"); //返回值为 true
var num1=isNaN("48.98"); //返回值为 false
- isNaN() 函数通常用于检测 oarseInt() 函数和 parseFloat() 函数的结果,以判断它们标识的是否为合格的数字,也可以用 isNaN() 函数来检测算术是否错误。
2.1.2 自定义函数
- 与 Java 语言一样,JavaScript 需要先定义函数,然后才能调用函数。而在 JavaScript 中,定义函数的方式有两种,分别是函数声明和函数表达式。
1.函数声明
-
在 JavaScript 中,函数声明由关键字 function、函数名、一组参数及大括号中待执行的 JavaScript语句组成。
-
语法
function 函数名(参数1,参数2,。。。。。){
//JavaScript 语句;
[return 返回值]
}
- function 时定义函数的关键字,必须有;
- 参数是函数的参数。
- 因为JavaScript 本身是弱类型语言,所以它的参数没有类型检查和类型限定。
- 函数中的参数是可选的,根据函数是否带参数,可分为不带参数的无参函数和带参数的有参函数。
- 不带参数语法
function 参数名(){
//JavaScript 语句;
}
- return 语句用来规定函数返回的值。
- 要执行一个函数,必须先调用这个函数,当调用函数时,必须指定函数名及其后面的参数(如果有参数)。函数的调用一般和元素的事件结合使用。
- 语法
事件名="函数名()";
- 示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input type="button" onclick="study()" value="显示5次欢迎学习 JavaScript">
<script type="text/javascript">
function study()
{
for (let i = 0; i <5 ; i++) {
document.write("<h4>欢迎学习 JavaScript</h4>")
}
}
</script>
</body>
</html>
- study() 是创建的无参函数;
- onclick 标识按钮的单击事件,当单击按钮时调用函数 study()。
效果图
- 运行一次,页面只能输出5行 “欢迎学习 JavaScript” 。如果需要根据用户的要求每次输出不同的行数,需要用到有参构造函数。
- 语法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<input name="btn" type="button" value="显示5次欢迎学习 JavaScript" onclick="study(prompt('请输入显示欢迎学习 JavaScript 的次数',''))"/>
<script type="text/javascript">
function study(count)
{
for (let i = 0; i <count ; i++) {
document.write("<h4>欢迎学习 JavaScript</h4>")
}
}
</script>
</body>
</html>
- count 表示传递的参数,不需要定义数据类型,将 prompt() 方法返回的值作为参数传递给函数 study(count)。
2.函数表达式
- 在 JavaScript 中,把一个函数赋给一个变量,此时形成了函数表达式。
- 语法
var 变量=function(参数1,参数2,参数3,....){
//JavaScript 语句;
}
- 既然有两种定义函数的发昂视,说明二者一定有不一样的地方。
- 下面使用函数声明的方式定义两个函数名都为 f1() 的函数。
- 使用函数表达式的方式定义脸啊哥哥函数名都为 f2() 的函数。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
//函数声明
function f1(){
console.log("今天天气真好!");
}
f1();
function f1(){
console.log("今天天气好晴朗,处处好风光");
}
f1();
var f2=function (){
console.log("哇");
}
//函数表达式
f2();
var f2=function (){
console.log("娃哈哈~");
}
f2();
</script>
</body>
</html>
- 使用函数声明的方式定义两个函数名相同的函数,后面的函数会覆盖掉前面的函数;
- 而使用函数表达式的方式定义函数,会从上到下逐行执行代码输出结果。
2.1.3 函数自调用
- 与 Java 不同的是,在自定义函数中,如果函数有名字,如 “function study(){}”,则被称为命名函数;
- 如果函数没有名字,如"function(){}",则被称为匿名函数。
(function(){
//函数体
})();
-
将 “function(){}” 匿名函数放在一对"()" 中,就实现了调用,被称为函数自调用。
-
特点
- 没有名字;
- 在声明的同时直接调用;
- 不会出现命名冲突。
2.1.5 回调函数
//字符串类型作为参数使用
function f1(x,y){
console.log(x+y);
}
f1("hello","你好");
function f2(x){
console.log(x);
}
f2(true);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
function f1(fn){
console.log("f1函数调用了");
fn();
}
function f2(){
console.log("f2函数调用了");
}
f1(f2);
</script>
</body>
</html>
- f2 函数作为参数传递到 f1() 中,并且在 f1() 函数中执行 fn() 函数,这时,f2() 函数可以被称作回调函数。
- 如果没有指定函数名称,可以被称作匿名回调函数。
2.2 局部变量和全局变量
- 在 JavaScript 中,根据变量作用范围的不同,可分为局部变量和全局变量。
2.2.1 局部变量和全局变量的概念及使用
- 局部变量实在函数内部声明的变量(必须使用 var) ,只能在函数内部访问它。特点是可以在不同的函数中使用名称相同的局部变量。
- 全局变量是在函数外声明的变量,网页上的所有脚本和函数都能访问它。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
//全局变量
var x=10;
function f1()
{
//局部变量
var y=5;
console.log(x);
console.log(y);
}
f1();
</script>
</body>
</html>
- 全局变量和局部变量的区别:作用域不同、声明位置不同、生存期不同。
- 作用域:局部变量仅作用在函数中,而全局变量作用于整个脚本。
- 声明位置:局部变量声明的位置在函数中,而全局变量可以声明在使用之前的任何位置。
- 生存期:局部变量在函数运行以后被删除,而全局变量在页面关闭后被删除。
2.2.2 隐式全局变量
- 局部变量实在函数内部声明的变量(必须使用var)。如果变量声明时没有var,责备称为隐式全局变量。
- 语法
var a1=1; //全局变量
a2=2; //隐式全局变量
- 在函数内部声明一个局部变量
function f1(){
num=200; //num按理说应该是一个局部变量
}
f1(num);
- num本应时局部变量,但没有使用 var 来声明,所以变成了一个隐式全局便令,在函数外部可以访问到num。
2.3 作用域和作用域链
2.3.1 作用域和块级作用域
- 作用域(Scope) 就是变量与函数的可访问范围,即作用域控制这变量与函数的可见性和生命周期。
- 块级作用域是由大括号限定的。在块级作用域下,所有的变量都定义在大括号内,从定义开始到大括号结束这个范围内可以使用,除了这个范围就无法访问。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script type="text/javascript">
//正常带有大括号的语句
{
var num=10;
}
console.log(num);//10
if(true)
{
var num=20;
}
console.log(num);//20
for (let i = 0; i < 5; i++) {
var num=30;//30
}
console.log(num);//30
//函数
function f1(){
var num=50;
}
f1();
console.log(num);
</script>
</body>
</html>
-
结果依次为 10、20、30 会报错。
-
在前三种大括号的情况里面定义的变量,在大括号外面也能使用,即违背了块级作用域的概念。
-
结论
- JavaScript 没有块级作用域。
-
f1() 函数内部定义的变量 num 在外部无法访问,原因是在函数作用域下,变量只在函数内部存在。
2.3.2 作用域链
- 当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级执行上下文的变量对象中查找,一直找到全局上下文的变量对象,即全局对象。
- 这样由多个执行上下文的变量对象构成的链表就被成为作用域链(Scope Chain)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>作用域链</title>
</head>
<body>
<script type="text/javascript">
var num=10; //在script标签里面定义的变量,就是0级作用域
function f1(){
var num=20; //1级作用域
function f2(){
var num=30; //2级作用域
function f3(){
var num=50; //3级作用域
console.log(num); //50
}
f3();
}
f2();
}
f1();
</script>
</body>
</html>
- 运行时会发现,控制台输出的值为50.
- 根据作用域链的概念,一开始执行函数时,现在内部找变量,在内部已经找到,因此就得到了 50.
- 如果 3 级作用域中没有 var num =50,则会向上一级查找,那么输出的就是30.
- 如果 2 级作用域没有 var num=30,就会继续向上找,直到找到为止。
- 如果最终没有找到,则会报错。
2.4 闭包
- 在函数外部无法读取函数内的局部变量,而闭包是指有权访问另一个函数作用域中的变量的函数。
- 主要分为两部分
- 在函数的内部,在定义一个函数。
- 把内部的函数作为返回值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>闭包</title>
</head>
<body>
<script type="text/javascript">
function f1(){
var num=1;
function f2(){
alert(num)
}
returnf2;
}
var result=f1();
result();
</script>
</body>
</html>
-
f1() 外层函数中声明了一个内部函数 f2(),然后通过 f2() 去操作 f1() 的局部变量,最后把内部函数 f2() 作为返回值。
-
代码中的内部函数 f2() 就是闭包。
-
可以把闭包简单地理解成 “定义在函数内部的函数。”
-
闭包主要的作用
- 可以读取函数内部的变量
- 可以让这些变量的值始终保存在内存中。
-
闭包的缺点
- 由于闭包可以读取函数内部的变量,所以闭包可以在父函数外部改变父函数内部变量的值。
- 闭包会是的函数中的变量都被保存在内存中,所以内存消耗大。
不能滥用闭包,否则会造成网页性能的问题。
2.5 事件
事件 | 介绍 |
---|---|
onload | 一个压敏啊或一幅图像完成加载。 |
onclick | 鼠标单击某个对象。 |
onmouseover | 鼠标指针移到某元素上。 |
onmouseout | 鼠标指针离开某元素 |
onkeydown | 某个键盘按键被按下 |
onchange | 域的内容被改变。 |
读取函数内部的变量
- 可以让这些变量的值始终保存在内存中。
- 闭包的缺点
- 由于闭包可以读取函数内部的变量,所以闭包可以在父函数外部改变父函数内部变量的值。
- 闭包会是的函数中的变量都被保存在内存中,所以内存消耗大。
不能滥用闭包,否则会造成网页性能的问题。
2.5 事件
事件 | 介绍 |
---|---|
onload | 一个压敏啊或一幅图像完成加载。 |
onclick | 鼠标单击某个对象。 |
onmouseover | 鼠标指针移到某元素上。 |
onmouseout | 鼠标指针离开某元素 |
onkeydown | 某个键盘按键被按下 |
onchange | 域的内容被改变。 |