题目
1.说一下对变量提升的理解
2.说明this几种不同的使用场景
3.创建10个<a>标签,点击时弹出对应序号
4.如何理解作用域
5.实际开发中闭包的应用
知识点#####
- 执行上下文
范围:一段<script>或者一个函数 或者eval代码
全局:变量定义、函数声明 (提前拿出来) 针对一段<script>
函数:变量定义、函数声明、this、arguments (提前拿出来) 针对一个函数
eval不常用,也不推荐大家用。
在一段js代码拿过来真正一句一句运行之前,浏览器已经做了一些“准备工作”,在“准备工作”中完成了哪些工作:
1.变量、函数表达式——变量声明,默认赋值为undefined;
2.this——赋值;
3.函数声明——赋值;
这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。
ps:注意函数声明和函数表达式的区别
//函数声明 function fn(){ //..... } //函数表达式 var fn1=function(){ //..... }
//全局console.log(a); //undefined var a=100 fn('zhangsan') //zhangsan 20 function fn(name){ //函数 console.log(this); //Window console.log(arguments); //"zhangsan" age=20 console.log(name,age); var age //age会提前 }
- this
this要在执行时才确认值,定义时无法确认
var a={ name:'A', fn:function(){ console.log(this.name); } } a.fn() //this===a a.fn.call({name:'B'}) //this==={name:'B'} var fn1=a.fn fn1() //this===Window
- - 作用域
js没有块级作用域
if(true){ var name='zhangsan' } console.log(name); //zhangsan
只有函数和全局作用域
var a=100 function fn(){ var a=200 console.log('fn',a) } console.log('global',a) //global 100 fn() //fn 200
- 作用域链
自由变量
var a=100 function fn(){ var b=200 console.log(a) //当前作用域没定义的变量,即'自由变量' console.log(b) } fn() //100 200
调用在当前作用域不存在的变量,便会向父级作用域查找。需要注意的是,父级作用域是函数定义时产生的,并非函数调用时。
var a=100 function F1(){ var b=200 function F2(){ var c=300 console.log(a) //a是自由变量,在F2中未找到便向父级作用域F1查找,仍未找到,继续向上查找,在Window中找到 console.log(b) //b是自由变量 console.log(c) } F2() } F1() //100 200 300
- - 闭包
使用场景,函数作为返回值;函数作为参数传递
//闭包的使用场景:函数作为返回值 function F1(){ var a=100 //返回一个函数 return function(){ console.log(a) //自由变量,父作用域查找,仍未找到,继续向上查找,在Window中找到 } } //f1得到一个函数 var f1=F1() var a=200 f1() //100
//闭包的使用场景:函数作为参数传递 function F1(){ var a=100 return function(){ console.log(a) //自由变量,父作用域查找 } } var f1=F1() function F2(fn){ var a=200 fn() } F2(f1) //100
#####解题#####
**1.说一下对变量提升的理解**
执行上下文的知识:http://www.jianshu.com/p/a6d37c77e8db
在<script>或函数中,各个变量、函数的声明与定义会被提前
**2.说明this几种不同的使用场景**
this的几种执行情况:
- 作为构造函数执行
- 作为对象属性执行
- 作为普通函数执行
- call apply bind
//构造函数 function Foo(name){ this.name=name } var f=new Foo('zhangsan')
//对象属性 var obj={ name:'zhangsan', printName:function(){ console.log(this.name) } } obj.printName()
//普通函数 function fn(){ console.log(this); } fn() //window
//call apply bind function fn1(name,age){ alert(name) console.log(this) } fn1.call({x:100},'zhangsan',20) //({x:100} //apply fn1.apply({x:100},['zhangsan',20]) //({x:100} //call, apply方法区别是,从第二个参数起, call方法参数将依次传递给借用的方法作参数, 而apply直接将这些参数放到一个数组中再传递 //bind var fn2=function (name,age){ //bind在函数声明的形式后不可用,必须是函数表达式 alert(name) console.log(this) }.bind({y:200}) fn2('zhangsan',20) //{y: 200}
**3.创建10个```<a>```标签,点击时弹出对应序号**
//错误的写法 var i,a; for(i=0;i<10;i++){ //除了click函数内部,都为全局作用域,会被覆盖。因此最终 i 的值为10 //全局作用域 a = document.createElement('a'); a.innerHTML = i+'</br>' ; a.addEventListener('click',function(e){ e.preventDefault(); alert(i); //i为自由变量,向上去父作用域查找时,值已经变成10. 因为click事件执行时,其它部分早已执行完毕。 }) document.body.appendChild(a); }
//正确的写法 var i for(i=0;i<10;i++){ //多包了一层,除了click函数,其它变量的作用于都变成了函数作用域,而不是全局作用域,因此不会被覆盖。相当于创建了10个函数 (function(i){ //函数作用域 var a=document.createElement('a') a.innerHTML=i a.addEventListener('click',function(e){ e.preventDefault() alert(i) //i为自由变量,向上去父作用域查找,就找到调用时的i值 (加粗处) }) document.body.appendChild(a) })(i) }
**4.如何理解作用域**
回答要点:
自由变量
作用域链,即自由变量的查找
闭包的两个场景
**5.实际开发中闭包的应用**
//闭包实际应用中主要用于封装变量,收敛权限 function isFirstLoad(){ var _list=[] return function(id){ if(_list.indexOf(id)>=0){ return false }else { _list.push(id) return true } } } //使用 var firstLoad=isFirstLoad()9 firstLoad(10) //true firstLoad(10) //false firstLoad(20) //true //在isFirstLoad函数外,无法修改_list的值