持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第13天,点击查看活动详情
函数声明与表达式的联系与区别
联系
它们都是一个函数对象, 调用方式没有什么不同
区别
- 浏览器在执行js代码前, 会先扫描代码, 对于函数声明会进行处理, 而对于函数表达式不会优先处理
- 浏览器如何处理函数声明呢? 浏览器在扫描到函数声明时, 会创建这个函数, 然后将函数的引用赋值给一个变量, 而这个变量名就是该函数名
- 浏览器对于函数表达式的处理跟对其它变量的处理逻辑是一样的
- 在调用位置上是不同的, 你可以在任何位置调用一个函数声明的函数, 而只能在函数表达式的后面调用该函数
- 对于函数声明是隐式的将函数引用同事赋值给一个变量, 对于函数表达式是显式的将函数引用赋值给一个变量
提升
使用函数声明来定义的函数, 你可以在任何地方声明这个函数, 也可以在任何地方调用函数声明的函数, 这就是函数提升
函数声明
function 函数名() {
// 函数体
}
函数表达式
let 变量名 = function() {
// 函数体
}
// 函数声明
function test1() {
console.log('test1');
}
// 函数表达式
let test2 = function() {
console.log('test2');
}
函数作为参数
let arr = [ {name: 'shaosiming', age: 16}, {name: 'dasiming', age: 18}, {name: 'tianming', age: 9}, {name: 'yuer', age: 8}, {name: 'shaoyu', age: 10} ];
// 按年龄从小到大排序
// arr.sort((a, b)=>{
// return a.age - b.age;
// })
// 按姓名排序
arr.sort((a, b)=>{
return (a.name > b.name ? 1 : (a.name === b.name ? 0 : -1));
})
console.log(arr);
函数作为返回值
function add(a, b) {
return a + b;
}
function sub(a, b) {
return a - b;
}
function getFunc(str) {
if (str === '+') {
return add;
} else if (str === '-') {
return sub;
}
}
console.log(getFunc('+')(3, 5));
console.log(getFunc('-')(3, 5));
匿名函数
在js中匿名函数的使用频率是超级高的, 这不仅大大方便了我们的编码
在使用匿名函数的时候, 我们还可以使用一些空格和换行让代码更易读
例如我们在绑定onload事件的时候, 就可以将一个匿名函数赋值给onload这个事件
// 第一种方式
// function init() {
// console.log("load finished!");
// }
// window.onload = init;
// 第二种方式
window.onload = function() {
console.log("load finished...!");
}
函数的嵌套
在函数内部使用嵌套函数的规则, 其实与使用全局函数的规则是一样的
在函数内部使用函数声明创建的嵌套函数, 则在该函数内部的任何地方都可调用这个嵌套函数
在函数内部使用函数表达式创建的嵌套函数, 则只能在嵌套函数表达式后才是可调用的
function test3() {
test33();
console.log('test33声明前');
function test33() {
console.log('test33...');
}
console.log('test33声明后');
test33();
}
function test4() {
// test44(); // error Cannot access 'test44' before initialization
console.log('test44声明前');
let test44 = function() {
console.log('test44...');
}
console.log('test44声明后');
test44();
}
闭包
闭包 = 函数 + 环境
闭包作为返回值
如下面这样, 在test5中定义的test55这个函数, 在该函数内部又使用了外部变量b, 然后将test55作为返回值return
那么test55函数和变量b就一块组成了闭包
// 闭包作为返回值
let a = 3;
function test5() {
let b = 5;
function test55() {
return b;
}
return test55;
}
console.log(test5()());
闭包作为参数
而对于makeTimer这个函数, callback函数和msg形参形成闭包, 这个闭包作为实参被setTimeout调用
// 闭包作为实参
function makeTimer(msg) {
function callback() {
alert(msg);
}
setTimeout(callback, 2000);
}
makeTimer("shaosiming is nice");
闭包作为事件处理程序
在下面代码中, button标签绑定了一个单击事件, 并且该事件中使用了count这个外部变量, 那么该事件处理程序和变量count就组成了闭包
<body>
<div id="msg">你点击了0次</div>
<button id="click">click me</button>
</body>
<script>
window.onload = function() {
let msg = document.getElementById('msg');
let btn = document.getElementById('click');
let count = 0;
btn.onclick = function() {
count++;
msg.innerHTML = `你点击了${count}次`;
}
}
</script>