1.作为其他变量的值
函数作为其他变量的值。可以直接调用;
1 <!DOCTYPE html> 2 <html lang="zh"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <meta http-equiv="X-UA-Compatible" content="ie=edge"> 8 <title>Document</title> 9 </head> 10 11 <body> 12 13 <script> 14 15 16 17 function foo(x, y) { 18 if (x > y) { 19 return x; 20 } else { 21 return y; 22 } 23 } 24 25 // 将 foo 函数作为变量 bar 的值 26 var bar = foo; 27 28 console.log(foo(12, 88)) 29 console.log(bar(12, 66)) 30 31 </script> 32 </body> 33 34 </html>
2.作为对象的属性值
当函数作为对象的属性值存在时,我们通常把它称为对象的方法。例如,obj 对象的 sayName() 方法。
1 <script> 2 3 // 当函数作为对象的属性值存在时,我们通常把它称为对象的方法。例如,obj 对象的 sayName() 方法。 4 var obj = { 5 name: '张康', 6 sayName: function () { 7 return this.name; 8 } 9 }; 10 11 12 </script>
3.作为其他函数的参数 (回调)
callback 函数是bar()函数的参数,foo()函数是callback()函数的实参
1 <script> 2 // 我们之前遇到的将函数作为其他函数的参数的用法 3 // ele.addEventListener('click', function(){}) 4 // $.getJSON('url', function(data, status, xhr) {}) 5 6 // 定义函数 foo 7 function foo(max) { 8 console.log(max) 9 } 10 11 // 定义函数 bar 12 function bar(a, b, callback) { 13 var max = -1; 14 15 if (a > b) { 16 max = a; 17 } else { 18 max = b; 19 } 20 // 在 bar 函数中调用传入的函数 21 callback(max) 22 23 } 24 25 // 将 foo 函数作为 bar 函数的实参 26 bar(12, 99, foo) 27 28 29 // 上面的代码可以被简写成如下形式: 30 // function bar(a, b, callback) { 31 // if (a > b) { 32 33 // callback(a) 34 // } else { 35 // callback(b) 36 // } 37 // } 38 39 // bar(12, 99, function (max) { 40 // console.log(max) 41 // }) 42 43 44 45 46 </script>
4.作为其他函数的返回值(闭包)
什么是闭包?闭包就是在js中变量的作用域属于函数作用域, 在函数执行完后,作用域就会被清理,内存也会随之被回收,但是由于闭包函数是建立在函数内部的子函数, 由于其可访问上级作用域,即使上级函数执行完, 作用域也不会随之销毁, 这时的子函数(也就是闭包),便拥有了访问上级作用域中变量的权限,即使上级函数执行完后作用域内的值也不会被销毁。
概念:用一种特殊方法,让函数作用域内部的变量能够被外部访问
场景:如何保证函数内部的变量不被释放
1.子作用域还在使用该变量
2.return关键字,函数执行到这个关键字立马停止函数程序,返回return关键字后面的值,也可以是个函数(javascript里面所有的基础类型);
作用域的问题:
全局作用域:地球内(都可以访问)
局部作用域:国家内(自己国家(自己函数)可以访问)
GC机制:垃圾自动回收处理机制; 如果不及时回收以及释放空间 会造成内存泄漏
- 另一个需要注意的问题是,返回的函数并没有立刻执行,而是直到调用了
f()
才执行
1 <body> 2 3 <ul> 4 <li>列表项1</li> 5 <li>列表项2</li> 6 <li>列表项3</li> 7 <li>列表项4</li> 8 <li>列表项5</li> 9 <li>列表项6</li> 10 </ul> 11 12 <script> 13 14 // 基本示例: 15 // 定义函数 bar 16 // function bar() { 17 18 // var i = 0; 19 20 // // 定义函数 foo 21 // function foo() { 22 // console.log(i) 23 // i++; 24 // } 25 26 // // 将函数 foo 返回到函数外部 27 // return foo; 28 // } 29 30 // 闭包函数是连接函数内部和外部的桥梁。 31 // var fun = bar() 32 // fun(); 33 // fun(); 34 // fun(); 35 // 将函数作为其他函数返回值的使用场景: 36 37 var listItems = document.getElementsByTagName('li'); 38 39 // 通过为 dom 对象添加自定义属性 idx 来记录索引值 40 for(var i = 0, len = listItems.length; i < len; i++) { 41 listItems[i].idx = i; 42 listItems[i].onclick = function() { 43 console.log(this.idx) 44 }; 45 } 46 47 // 通过闭包函数记录索引值 48 // for(var i = 0, len = listItems.length; i < len; i++) { 49 50 // listItems[i].onclick = (function(idx) { 51 52 // return function() { 53 // console.log(idx) 54 // }; 55 56 // })(i) 57 // } 58 59 60 </script> 61 </body>
5.作为构造函数(定义对象)
普通函数:偏重于实现功能(业务逻辑)
构造函数:用来创建自定义对象的实例
- 构造函数与普通函数本质上没有什么区别,只不过是为了区分他们,我们 1. 习惯将构造函数的首字母大写 2. 在构造函数时,需要new 操作符
- 在使用new操作符调用函数时,具体发生了什么(nea操作符的作用)
1. 当我们使用 new 操作符调用一个函数时,函数内部会自动创建一个该对象的实例。
2. 我们可以在函数内部使用 this 关键字访问新创建的实例。
3. 函数调用结束时,新创建的对象实例会被自动地返回到函数外部。
4. 我们也可以在构造函数中手动地返回一个值,如果返回的是原始类型的数据,则会被忽略,如果返回的是引用类型的数据,则该数据会取代原本要返回的新实例。(画蛇添足的一步)
1 <script> 2 3 // 本地对象 Array/Function/Date... 4 5 // 普通函数,偏重于实现功能(业务逻辑) 6 function max (x, y) { 7 return x > y ? x : y; 8 } 9 10 // 调用普通函数 11 max(23, 45) 12 13 // 构造函数,用来创建自定义对象的实例 14 function Dog(dogName, dogAge) { 15 this.name = dogName; 16 this.age = dogAge; 17 } 18 19 // 调用构造函数 20 var dog1 = new Dog('哈士奇', 3); 21 var dog2 = new Dog('泰迪', 2); 22 23 console.log(dog1, dog2) 24 25 // 1. 当我们使用 new 操作符调用一个函数时,函数内部会自动创建一个该对象的实例。 26 // 2. 我们可以在函数内部使用 this 关键字访问新创建的实例。 27 // 3. 函数调用结束时,新创建的对象实例会被自动地返回到函数外部。 28 // 4. 我们也可以在构造函数中手动地返回一个值,如果返回的是原始类型的数据,则会被忽略,如果返回的是引用类型的数据,则该数据会取代原本要返回的新实例。 29 30 // 构造函数与普通函数本质上没什么区别,只不过为了区分它们,我们习惯将构造函数的首字母大写。 31 // 1. 构造函数的首字母需要大写。 32 // 2. 在构造函数时需要使用 new 操作符。 33 34 </script>