this指向
document.getElementById = (function(func){
return function(){
return func.apply(document,arguments)
}
})(document.getElementById) //用来修正this指向
var getId = document.getElementById //如果不写上述代码直接调用,单纯作为对象属性调用,this指向window
var div = getId('div1')
alert(div.id) //输出: div1
document.getElementById('div1').onclick = function(){
var func = function(){
alert(this.id)
}
func.call(this) //修正func中this指向
}
闭包
闭包暴露到外界的变量不会被销毁,所以可用来处理下列经典问题
<html>
<body>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<div>1</div>
<script>
var nodes = document.getElementsByTapName('div)
for(var i=0,len = nodes.length;i<len;i++){
nodes[i].onclick = function(){
alert(i) //弹出的都是5,因为click事件是异步触发的的,循环早已经结束
}
}
</script>
</body>
</html>
进行如下改造
for(var i=0,len=nodes.length;i<len;i++){
(function(i){
ndoes[i].onclick = function(){
console.log(i)
}
})(i) //跟处理普通闭包一样,因为i不会被销毁,先将i封闭起来
}
由此原理封装一个类型判断函数
var Type = {}
for(var i=0,type;type=['String','Array','Number'][i++]){
(function(type){
Type['is'+type] = function(obj){
return Object.prototype.toString.call(obj) === '[Object' + type + ']'
}
})(type)
}
Type.isArray([]) // true
Type.isString("str") //true
闭包的更多作用
1.封装变量(看书理解更透彻)
var mult = (function(){
var cache = {} //将cache缓存对象封装在闭包里作为私有变量
var calculate = function(){ //提炼函数,若函数很大,这个小函数可能还能在别处用到,代码复用
var a = 1
for(var i=0,l=arguments.length;i<1;i++){
a = a*arguments[i]
}
return a
}
return function(){
var args = Array.prototype.join.call(arguments,',')
if(args in cache){
return cache[args]
}
return cache[args] = calculate.apply(null,arguments) //apply的用处
}
})()
延续局部变量的寿命
img对象常用于数据上报,但由于生命周期,可能会数据还没全部传完,对象就被销毁,这时闭包变量又用上了
var report = function(src){
var img = new Image()
img.src = src
}
report('http://xxx.com/getUserInfo')
var report = (function(){
var imgs = []
return function(src){
var img = new Image()
imgs.push(img)
img.src = src
}
})() //无法销毁,保证图片上传的完整性
闭包和面向对象设计
闭包会造成一些变量无法及时销毁,所谓内存泄漏,但是让变量暴露在全局中也是泄漏,用闭包反而可以手动设置null,更好管理
Dom的循环引用会造成内存泄漏,要手动设置null
普通关于闭包代码
var extent = function(){
var value = 0;
return{
call:function(){
value++;
console.log(value)
}
}
}
var extent = extent()
extent.call() //1
extext.call() //2
extext.call() //3
改为面向对象写法
var extent = {
value:0,
call:function(){
this.value++
console.log(this.value)
}
}
extent.call()//1
extent.call()//2
extent.call()//3
直观简洁很多
好书,明晚接着总结。。。