函数定义/函数声明

JavaScript-函数基础知识_i++

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

函数的定义方式

JavaScript-函数基础知识_i++_02JavaScript-函数基础知识_for循环_03

<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);

JavaScript-函数基础知识_html_04

  • console.log(f.__proto__);

JavaScript-函数基础知识_i++_05

函数调用方式

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

JavaScript-函数基础知识_i++_06

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. 主线程执行完毕,依次执行微任务,宏任务