闭包.词法作用域#
Posted itly
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了闭包.词法作用域#相关的知识,希望对你有一定的参考价值。
JS程序的执行过程.
1.词法分析 . 语法分析阶段:变量声明(赋值阶段在执行阶段进行);函数声明带函数赋值.
2.函数表达式的变形
//函数表达式的变形
var fn=function foo(){
console.log("abc");
};
fn();//"abc" foo();//报错
2.词法作用域,作用域链,变量查找过程
按照书写个还是决定了变量可访问的范围,跟调用方式无关
var height =10;
setTimeout(function(){
var height2=30;
setTimeout(function(){
var height1 =80;
console.log(height2);//30
});
console.log(height1);//获取不到height1
});
3.函数具有独立的作用域,在函数内部的程序执行过程,也会有一套完整的预解析的步骤.
4.拷贝创建对象
/*拷贝创建对象的高级使用方式*/
function hightExtend(){
var key =0, i =0, len = arguments.length;
target =null;
if(len ==0){
returnfalse;
}elseif(len ==1){
return arguments[0];
}else{
i++;
target = arguments[0];
for(; i < len; i++){
for(key in arguments[i]){
target[key]= arguments[i][key];//把后面传入的对象遍历一下,但遍历每一个对象的属性
//添加到target元素上
}
}
}
}
//5.历史遗留问题
if(true){
function foo1(){
console.log(foo1);
}
}else{
function foo2(){
console.log(foo2);
}
}
//在ff.chrome中打印结果为f1,在旧版本中打印结果为f2
//规则规范,不允许在语法块中声明函数
6.跨作用域访问变量
/*
* 查找作用域中的变量:首先查找当前作用域是否定义了该变量,若果定义了就不会再继续查找
* */
function foo(a,b){
console.log(a);}
foo(1,4);
//函数的参数是在foo作用域执行的时候
//预解析:分析a是一个采纳数所以会向当前作用域添加一个变量a并且给a赋值,值是实参的值
//代码执行;参数已经有值了 可以直接获取
var num =10;
function fn(num){
console.log(num);//undefined
// 首先查找当前作用域是否定义了num
}
3.闭包 模块化 闭包最常见的使用场景
//沙箱:模块化,沙箱是一个隔离的环境,最大的好处就是避免全局变量的污染.
var model =(function(){//一个匿名的立即执行函数
var price =900;//这是一个model局部的变量,外界无法访问,无法修改
//有效的保障了属性的安全性
return{
pay:function(money){
if(money < price){
console.log("您的消费不够,请继继续消费");
}else{
console.log("恭喜成为VIP");
}
}
}
})();
console.log(model.pay(800));//"消费不够.." undefined
model.pay(1000);//"VIP..."
//千万注意不用打印,pay函数本身就有输出,如果在console.log中
//会输出函数的返回值.
//在面向对象中使用沙箱
//应用场景:在页面初始化的时候要用到f1,f2,f3三个函数
//这三个函数不想让外界访问,需要把这单个方法声明成为构造函数
//内部私有的变量
var songManger =(function(){
function f1(){
console.log("函数f1的方法");
}
function f2(){
console.log("函数f2的方法");
}
function f3(){
console.log("函数f4的方法");
}
functionSongManger(){//声明一个构造函数
}
SongManger.prototype={//在原型对象上扩展方法
init:function(){
f1();
f2();
f3();
}
};
// return SongManger;//注意这个返回的是构造函数,使用之前需要先实例化一下
returnnewSongManger;//把构造函数返回,实例化一下,这样外边就不需要实例化了
})();
songManger.init();//
/*
* 闭包实现缓存
* 属性:有个键--值 --->所以可以将缓存数据存放在一个对象中
* 方法:缓存存储 setCache
* 缓存的获取 getCache
* */
function configCache(){
var obj={};//设置一个内部的对象 用来存储缓存数据;这个属性是私有的
//对外暴露两个公共的方法
return{
setCache:function(k,v){//设置缓存
obj[k]=v;
},
getCache:function(k){//获取缓存
return obj[k];
}
};
}
var conf = configCache();
console.log(conf);
conf.setCache(1,\'sdwqecwqv\');
console.log(conf.getCache(1));//sdwqecwqv
/*
* 注意下面这种情况,两次configCache()会产生不同的执行环境
* */
configCache().setCache(1,\'sdwqecwqv\');
console.log(configCache().getCache(1));//undefined
/*
* 使用立即执行函数
* */
var cacheConfig =(function(){
var obj={};
return{
setCache:function(k,v){
obj[k]=v;
},
getCache:function(k){
return obj[k];
}
}
})();
// 给所有的 li 提供点击事件, 在点击后 弹出目录中的文本内容
<body>
<ul>
<li>aaa</li>
<li>bbb</li>
<li>ccc</li>
<li>ddd</li>
<li>eee</li>
</ul>
</body>
<script>
var list = document.getElementsByTagName(\'li\');
for(var i =0; i < list.length; i++){
list[ i ].onclick =function(){
//alert(i);//i=5
//alert( list[ i ].innerhtml );//报错
//alert(this.innerHTML);//一种解决方案
//list[4]:eee list[5]:undefined
};
}
</script>
//第二种解决方案:闭包
// for ( i = 0; i < list.length; i++ ){
var j=i;
// list[ i ].onclick = (function (j) {
// return function (){
// alert(list[j].innerHTML);
// }
// }(i));
// }
//caller
function fn1(){
console.log(fn1.caller);//打印的是fn1函数体
}
function fn2(){
fn1();
}
fn2();
console.log(fn1.caller);//null caller方法只能在函数调用的时候获取
//问题理解的关键: 内层函数保存的j,当执行的时候从哪里取的??
//每次绑定都会执行一个外层函数,都会产生一个新的作用域,内层函数会保存这个新作用域中的变量
var list = document.getElementsByTagName("li");
for(var i=0;i<list.length;i++){
list[i].onclick=(function(){
var j=i;//每次绑定都会执行外层函数,都会保存一个J的变量在内层函数中
returnfunction(){
console.log(list[j].innerHTML);
}
})();
}
//结论:
//闭包保存一个数据,让外层函数执行一次
//闭包保存多个数据,让外层函数执行多次
var list = document.getElementsByTagName(\'li\');
for(var i =0; i < list.length; i++){
//希望每一次绑定的时候,就保存一下当前的索引
// 多次绑定就保存多个索引——>利用闭包,保存多个数据:让外层函数执行多次
list[i].onclick =(function(){
var j=i;
returnfunction(){//内层函数由浏览器帮助我们调用的
alert(list[j].innerHTML);
}
}());//调用了5次,外层函数调用了五次,就会产生5个独立的作用域,这几个作用域中的j变量的值都不一样
}
以上是关于闭包.词法作用域#的主要内容,如果未能解决你的问题,请参考以下文章