JavaScript(函数,作用域和闭包)
目录
一,什么是函数
类似于Java中的方法,是完成特定任务的代码语句块
特点
使用更简单
不用定义属于某个类,直接调用执行
分类
系统函数
自定义函数
1.1,常用系统函数
1.将字符串转换为整型数字
parseInt("字符串");
<body>
<input type="button" value="求和" onclick="qiuhe()">
</body>
<script>
var num1 = parseInt("56.64"); //返回值为56
var num2 = parseInt("123abc"); //返回值为123
var num3 = parseInt("hello999"); //返回值为NaN
console.log(num1,num2,num3);
function qiuhe(){
var n1 = prompt("请输入第一个数")
var n2 = prompt("请输入第二个数")
var num1=parseInt(n1)
var num2=parseInt(n2)
if(isNaN(num1)||isNaN(num2)){
alert("有一个不是数字");
}else{
document.write(num1+num2)
}
}
</script>
js示例1
从下标为0起,依次判断每个字符是否可以转换为一个有效数字
如果不是有效数字,则返回NaN,不再继续执行其他操作
如果是有效数字,则该函数将查看下标为1的字符,进行同样的测试,直到发现非有效数字的字符或全部检测完为止
2.将字符串转换为浮点型数字
parseFloat("字符串");
var num1 = parseFloat("3.1415926"); //返回值为3.1415926
var num2 = parseFloat("123abc"); //返回值为123
var num3 = parseFloat("hello999"); //返回值为NaN
var num4 = parseFloat("52.18.97"); //返回值为52.18 如果有两个小数点则第二个小数点无效
console.log(num1,num2,num3);
3.检查其参数是否是非数字
isNaN(x);
var num1=isNaN("20.5"); //返回值为false
var num2=isNaN("123abc"); //返回值为true
var num3=isNaN(48.98); //返回值为false
console.log(num1,num2,num3);
通常,使用isNaN()函数检测parseInt()和parseFloat()的运算结果,判断它们表示的是否是合格的数字;也可以使用isNaN()函数检测
操作数是否有错误,例如:用0作为除数的情况
1.2,函数声明
由关键字function、函数名、一组参数及置于括号中的待执行的JavaScript语句组成
语法
// JavaScript是弱数据类型,对于函数参数没有类型检查和类型限定
function 函数名([参数1[, 参数2[, 参数3,…] ] ]) {
//JavaScript语句;
[return 返回值] // return可有可无
}
调用函数
// 一般和表单元素的事件一起使用
事件名=“函数名([参数值1[, 参数值2[, 参数值3,…] ])";
函数声明——调用无参函数
// 定义并调用无参函数,输出5次“你好”
<body>
//单击此按钮时,调用函数func1( ),执行函数体中的代码
<input type="button" value="点我执行" onclick="func1()">
</body>
<script>
function func1(){
for(var i=0;i<5;i++){
document.write("<h1>你好"+i+"</h1>")
}
}
</script>
js示例2
函数声明——调用有参函数
// 键盘接受“你好”输出行数,并按指定数字输出到网页
<body>
<input type="button" value="点我执行" onclick="func1(prompt('请输入显示你好的次数:'))">
</body>
<script>
function func1(count){
for(var i=0;i<5;i++){
document.write("<h1>你好"+i+"</h1>")
}
}
</script>
js示例3
1.3,函数表达式
将函数赋给变量
定义函数
var 变量 = function([参数值1[, 参数值2[, 参数值3,…] ]) {
//JavaScript语句;
};
调用函数
变量([参数值1[, 参数值2[, 参数值3,…] ]);
函数表达式
// 使用函数声明的方式定义两个函数名都为f1()的函数
f1();
function f1(){
var num3 = 100;
console.log(num3)
}
function f1(){
console.log("今天天气很好!")
}
f1();
function f1(){
console.log("今天天气好晴天,处处好风光");
}
f1();
// 使用函数表达式方式定义两个函数名都为f2()的函数
var f2 = function(){
console.log("哇~");
}
f2();
var f2 = function(){
console.log("娃哈哈~");
}
f2();
使用函数声明方式定义两个同名的函数时,后面的函数将会覆盖前面的函数;
使用函数表达式方式定义同名的函数时,会从上到下,逐行执行代码,并输出结果
二,预解析
顾名思义就是提前解析代码
主要完成两项工作
其一,变量的声明会提前
其二,函数的声明也会被提前
// 预解析可以把变量的声明提前
console.log(num); //undefined
var num=10;
// 预解析可以把函数的声明提前
f1();
function f1() {
var num=100;
console.log(num); //100
}
2.1,函数自调用
自定义函数分类
命名函数
匿名函数
语法
(function() {
//函数体
})();
匿名函数的特点
函数没有名字,在声明的同时便直接调用
好处
同名函数之间不会有冲突
( function(){
console.log("立即执行函数");
})();
2.2,回调函数
注意
如果没有指定回调函数的名称,则称之为 匿名回调函数
function f1(fn){
console.log("f1");
fn()
};
function f2(){
console.log("f2");
return 1
};
f1(f2); // 执行命名回调函数,注意f2后面不能加()
function f1(fn){
console.log("f1");
fn()
};
f1(function(){ // 匿名函数
console.log("我没有名字!");
})
三,变量的作用域
根据变量作用范围不同,分类
局部变量
在函数内部声明的变量(必须使用var)
只能在函数内部访问它
可以在不同的函数中使用名称相同的局部变量
全局变量
在函数外声明的变量
网页的所有脚本和函数都能访问它
var x = 10;
function f1(){
var y = 5;
console.log(x); // 10
console.log(y); // 5
}
f1();
console.log(x); // 10
console.log(y); // y is not defined
局部变量与全局变量的区别
区别 | 局部变量 | 全局变量 |
---|---|---|
作用域 | 仅作用在函数中 | 作用在整个脚本 |
声明位置 | 函数中 | 使用之前的任何位置 |
生存期 | 在函数运行以后被删除 | 在页面关闭后被删除 |
3.1,隐式全局变量
如果变量声明时,没有使用关键字var,则被称为隐式全局变量
示例
var a1 = 1; //全局变量
a2 = 2; //隐式全局变量
如果在函数内部声明变量时,没有使用关键字var,则也是隐式全局变量
function f1(){
var num = 100;
}
f1();
console.log(num); // 函数会报错
function f1(){
num = 100;
}
f1();
console.log(num);
与解析:
1.会把全局变量的“声明”提前
2.提前声明函数,但是函数内部的代码是不执行的
局部变量:必须在函数内部使用var/let声明,如果不使用,则称为隐式全局变量
隐式全局变量:只有在执行后使用,
全局变量和局部变量可以重名,使用就近原则
四,作用域与块级作用域
作用域
是变量与函数的可访问范围
控制着变量与函数的可见性和生命周期
块级作用域
由花括号“ { } ”限定
所有的变量都定义在花括号内
变量从定义开始到花括号结束的范围内可以使用
使用场景
正常带有大括号的语句
条件语句
循环语句
函数
正常带有大括号的语句
{
var num = 10;
}
console.log(num); // 10
// 条件语句
if(true){
var num = 20;
}
console.log(num); // 20
// 循环语句
for(var i=0;i<5; i++){
var num = 30;
}
console.log(num); // 30
// 函数
function f1(){
var num = 50;
}
f1();
console.log(num); // num is not defined
五,作用域链
Scope Chain
是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);
}
f3();
}
f2();
}
f1()
六,闭包
如何在函数外部读取函数内的局部变量呢?
闭包(closure)
能够读取其他函数内部变量的函数
是将函数内部和函数外部链接起来的桥梁
实现步骤
在一个函数的内部,再定义一个函数
把内部的函数作为返回值
特性
函数嵌套
内部函数可以访问外部函数的变量
参数和变量不会被回收
最典型的应用
实现回调函数
// 1.在函数内部定义一个函数
// 2. 把内部函数作为外部函数的返回值
// 原理:利用了内部函数可以调用外部函数的变量
function f1(){
var num = 20;
function f2(){
alert(num);
}
return f2;
}
var result = f1();
result();
作用
可以读取函数内部的变量
让这些变量的值始终保存在内存中
缺点
在父函数外部,可以改变父函数内部变量的值
常驻内存,会增大内存使用量,使用不当很容易造成内存泄露