1、函数使用 1.1 函数声明和函数表达式 1.2 函数封装(自调用函数、闭包) 1.3 函数属性(arguments、callee) 1.4 构造函数 2、函数技巧 2.1 改变函数做用域(call/apply/bind) 2.2 for循环中的setTimeout问题修复
字符串和数组都是用来存储数据。须要作一些特定的事情的时候,咱们就会会用函数封装起来。javascript
声明一个函数能够用函数声明
或者函数表达式
。html
function hello( name ) { some code ... } // 函数声明 var hello = function ( name ) { some code ... } // 函数表达式 // 变量提高 | 函数内部的变量未使用var声明,执行后会致使变量成为全局变量 var age = 22 function showAge(){ age = 23 console.log(age) } showAge() // 23 | 执行函数 console.log(age) // 23 | 测试全局变量age的值
实际项目中会引入不少外部JS文件,为了不彼此命名冲突。一般各自都会对内部函数进行封装。(如今更好的方案是使用模块化,模块化之后再总结)前端
自调用函数java
使用自调用函数,把整个JS文件的代码都封装在内。git
(function(){ // some code ... window.myApp = myApp() // 把对外访问的接口挂载在window上 })()
闭包封装es6
若是你内部使用的是函数表达式,而且不用var声明,变量依旧会泄露到全局。github
// a.js (function(){ function myApp() { // 定义showName方法 function showName(name) { console.log(name) } // 定义showAge方法 function showAge(age){ console.log(age) } // 返回一个对象 return { showName: showName, showAge: showAge } } window.myApp = myApp() })()
功能扩展跨域
引入上面的a.js文件,而且建立b.js来写程序主逻辑。数组
//b.js // 修改已有方法 myApp.showName = function (name) { console.log('Call me '+name) } // 定义新方法 myApp.showCity = function (city) { console.log(city) } myApp.showName('berg') // 可以访问 | berg myApp.showCity('NanChang') // 可以访问 | NanChang showName('berg') // 不能访问 | Uncaught ReferenceError: showName is not defined
arguments是用来存放实参的,能够经过下标访问实参的值。callee指向当前执行的函数,能够在递归的时候用。具体递归场景以及代码,请见MDN。闭包
function show(name,age) { console.log(name) // berg console.log(age) // 22 console.log(arguments) // ["berg", 22] console.log(arguments.callee) // function show(name,age) {} } show('berg',22)
ES6可使用Class实现继承,之后在单独总结ES6的时候会提到。推荐一个很是好的ES6系列教程,深刻浅出ES6
// 声明构造函数 Human function Human() { this.play = function(){ console.log('I\'m playing.') } } // 声明构造函数 Male function Male() { this.sex = 'male' } // 声明构造函数 Female function Female() { this.sex = 'female' } // 让Male和Female继承Human Male.prototype = new Human() Female.prototype = new Human() // 建立xiaoming对象而且测试继承结果 var xiaoming = new Male() console.log(xiaoming.sex) // male console.log(xiaoming.play()) // I'm playing. // 建立xiaohong对象而且测试继承结果 var xiaohong = new Female() console.log(xiaohong.sex) // female console.log(xiaohong.play()) // I'm playing.
当须要改变上下文的this的时候,可使用call/apply/bind。(更详细的解释请见ChokCoco,须要用call实现继承请见MDN)
/* 如下以数组合并为例子 * 使用不一样的方法以前,请确保a和b为默认值 */ var a = [1,2,3] // 测试用的默认值 var b = [4,5,6] // 测试用的默认值 a.push(b) // 直接使用push(不符合预期) console.log(a) // [1, 2, 3, Array[3]] // call方法(在这种状况下要逐个输入参数,不太方便) Array.prototype.push.call(a,4,5,6) console.log(a) // [1, 2, 3, 4, 5, 6] // apply方法(第二个参数直接传入数组,很是适用这种场景) Array.prototype.push.apply(a,b) console.log(a) // [1, 2, 3, 4, 5, 6] // bind方法 Array.prototype.push.bind(a,4,5,6)() // 注意看,这里须要加一个自动执行函数 console.log(a) // [1, 2, 3, 4, 5, 6]
setTimeout有本身的this。若是在外层放一个for循环,意味着会一次性执行完,而没有起到延时的做用。解决方案是使用闭包。此处主要参考JavaScript 秘密花园
// 使用闭包前 for(var x = 0; x<10; x++) { setTimeout(run,1000) // 10 } function run() { console.log(x) } // 使用闭包后 for(var x = 0; x<10; x++) { setTimeout((function (x) { return function() { console.log(x) // 0 1 2 3 4 5 6 7 8 9 } })(x),1000) }
全文主要参考如下网站
推荐的教程
全文主要是参考MDN写出的总结。外加ChokCoco和JavaScript 秘密花园中的细致分析,以及本身平时的一些总结写成此文。
文中的错误还望可以指出,会及时作出修改(哪怕是错别字)。Vue的基本理念如今差很少搞清楚了,大概在下周,会对Vue作一个总结(其实官方文档是最好的总结 ^_^)。