函数定义/函数声明
1. 自定义函数(命名式函数)
function fn() {}
2. 函数表达式(匿名函数)
var fun = function(){}
3. new Function('参数1', '参数2', ... ,'函数体')
// 参数:空;函数体:console.log(123)
var f = new Function('console.log(123)');
f(); // 函数调用
// 参数:a, b;函数体:console.log(123)
var f = new Function('a', 'b', 'console.log(a + b)');
f(1, 2);
4. 所有函数都是Function的实例(对象)
console.dir(f);
console.log(f instanceof Object); // true
函数的定义方式
<script>
var f = new Function('a', 'b', 'console.log(a + b)');
f(1, 2); // result: 3
</script>
- console.log(f instanceof Object); // true
-
console.log(f.prototype);
-
console.log(f.__proto__);
函数调用方式
1. 普通函数
function fn() {
console.log(123);
}
fn(); // 调用方式一
fn.call(); // 调用方式二
2. 对象的方法
var o = {
sayHi: function(){
console.log('hello, world');
}
}
o.sayHi(); // 函数调用(对象.方法名)
3. 构造函数
function Start() {};
new Start(); // 函数调用(实例化一个对象)
4. 绑定事件函数(匿名函数)
btn.onclick = function() {}; // 点击按钮时调用函数
5. 定时器函数
setInterval(function() {}, 1000) // 每隔1s执行一次
6. 立即执行函数 // 自动调用(自执行函数)
(function(){})() // 创建闭包
(function(){
console.log('hello, world');
})()
匿名函数的用法(2种方式)
- 赋值函数
- 自执行函数
自执行函数
var b = function() {}; //声明
b(); // 调用
自执行函数 = 声明 + 调用
(b)();
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JS Test02...</title>
</head>
<body>
<script>
(function() {
console.log(123);
})()
</script>
</body>
</html>
浏览器加载index.html,log窗口输出123。函数没有被调用,直接运行。自执行函数可直接使用,可用作创建命名空间、插件等。
自执行函数的调用方式常见的有三种:
//1.方式一
(function(){
document.write('wo hao');
})();
//2.方式二
(function(){
document.write('hello');
}());
//3.方式三
[function(){
document.write('world');
}()];
参考链接:https://blog.csdn.net/weixin_44388523/article/details/86514627
实例:(知识点:自执行函数)
<script>
for (var i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, i*1000);
}
</script>
output:
5
5
5
5
5
原因:js中没有块级作用域,只有函数作用域。
1.首先执行for循环,设置5个定时器,定时器分别是0,1s,2s,3s,4s。
2.执行过程中需要打印i,i在for循环中定义。for循环执行结束后,i值为5。每次打印值为5
通过自执行函数解决以上问题
<script>
for (var i = 0; i < 5; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, i*1000);
})(i);
}
</script>
output:
0
1
2
3
4
方法2: ES6 使用let,块级作用域。i只能在for循环内部使用,for循环外部无法使用i,i会依次增加。
<script>
for (let i = 0; i < 5; i++) {
setTimeout(function() {
console.log(i);
}, i*1000);
}
</script>
output:
0
1
2
3
4
扩展:去掉function的参数i
console.log(i);向父元素寻找i,未找到。向for循环中找i,结果i为5。
实例2(知识点:自执行函数)
// test.js
for (var i = 0; i < 5; i++) {
setTimeout((function(i){
console.log(i);
})(i), i*1000);
}
在node环境中运行test.js,报错:
timers.js:390 throw new ERR_INVALID_CALLBACK(); ^ TypeError [ERR_INVALID_CALLBACK]: Callback must be a function
原因:
node环境中,setTimeout函数第一参数必须是函数。自执行函数运行的结果不是函数。
//index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JS Test02...</title>
</head>
<body>
<script>
for (var i = 0; i < 5; i++) {
setTimeout((function(i){
console.log(i);
})(i), i*1000);
}
</script>
</body>
</html>
浏览器打开index.html,运行结果如下:
0
1
2
3
4
浏览器中代码解析如下:
setTimeout((function(i){ //没有返回值
console.log(i);
})(i), i*1000);
相当于
setTimeout(unddefined,i*1000);
不存在异步操作。
实例3(知识点:异步调用、Promise)
setTimeout(function() {
console.log(1);
}, 0);
new Promise( r => {
console.log(2);
r();
console.log(3);
}).then( data => {
console.log(4);
})
console.log(5);
Event Loop 机制
主线程:2 3 5 4 1
异步
宏任务 setTimeout setInterval requestAnimationFrame
微任务 Promise mutationObserver interSectionObeser
1. setTimeout进入队列任务
2. r() 进入任务队列
3. 主线程执行完毕,依次执行微任务,宏任务