//------------------题目------------------------->
1.说一下对变量提升的理解
针对两个场景一个script、一个是构造函数中,它的变量的声明和定义
以及函数的声明都会被提前,放在前面,所以会导致我们有变量提升主观上的理解。(执行上下文的知识)
*1、变量定义
*2、函数声明(注意和函数表达式的区别)
2.说明this集中不同使用场景
*1、作为构造函数执行
*2、作为对象属性执行
*3、作为普通函数执行
*4、call apply bind
3.创建10个<a>标签,点击时候弹出来对应的序号
var i ;
for(i=0;i<10;i++){
//自执行函数,就是不用调用,只要定义完成,立即执行的函数
(function(i){
// 函数作用域
var a = document.createElement('a');
a.innerHTML = i+'<br>';
a.addEventListener('click',function(e){
e.preventDefault();
alert(i);//自由变量,要去父级作用域获取值
});
document.body.appendChild(a);
})(i);
}
//闭包或者作用域使用的问题
4.如何理解作用域
*自由变量
*作用域链,即自由变量的查找
*闭包的两个场景
5.实际开发中闭包的应用
//闭包是作用域知识点的实际应用
//闭包实际应用中主要用于封装变量,收敛权限\
// 判断用户是不是第一次加载
function isFirstLoad(){
//把存储数据的数据源存起来,其他外边拿不到
var _list = [];//变量前面有下划线,说明这个是私有变量
return function(id){
if(_list.indexOf(id) >=0){
return false;
}else{
//_list这里是自由变量,要去它定义的父作用域去找
_list.push(id);
return true;
}
}
}
//使用
var firstLoad = isFirstLoad();
firstLoad(10); //true
firstLoad(10); //false
firstLoad(20); //true
firstLoad(20); // false
//在isFirstLoad函数外边,根本不可能修改掉_list的值
//*******************知识点*******************************
一、执行上下文
范围:一段<script>或者一个函数
全局:变量定义、函数声明
【一段<script>会生成一个全局的执行上下文,执行之前先去
把变量定义、函数声明拿出来】
函数:变量定义、函数声明、this、arguments
**【针对一个函数,会出现一个函数执行上下文,函数执行之前
先把函数中的变量定义、函数声明、this、arguments(函数
中所有参数的集合)拿出来】**
PS:注意‘函数声明’和‘函数表达式’的区别:
【函数声明】:
//如果这里执行fn();不会报错;
/*这段程序执行之前会把声明的
函数提到前面去,先声明出来,执行不会报错*/
function fn(name){
age = 20;
console.log(name,age);
var age;
}
【函数表达式】:
(本质上执行的只是这个变量,并不是把函数声明提前了)
//在这里执行fn1();会报错;
/*所有var fn1,在执行之前不是个函数,在执行之前会把var fn1
提到前面去,并且赋值成undefined,var fn1并没有去执行*/
var fn1 =function(){};
/*在执行第一行之前,会把所有的变量的声明和函数声明都拿出来*/
// 写程序先定义会执行(增加代码可读性))
eg. 1.
/*
全局函数作用域(会把变量的声明,和函数的声明挪到前面去,
先声明了;函数的声明是把函数挪前面去了,变量的声明把变量挪
前面去了,并且赋值undefined,占位)
*/
console.log(a);//undefined
var a = 100;
eg.2.
fn('zhangsan');//'zhangsan' 20
function fn(name){
/*都会把变量提前,都会把函数提前*/
/*在函数执行之前,this、arguments已经确定了值*/
console.log(this);//window
/*["zhangsan",callee:function,
symbol{symbol.iteareator}:function]*/
console.log(arguments);
age = 20;
console.log(name,age);
var age;
}
二、this
1.this要在执行时才能确认值,定义时无法确认
1.作为构造函数执行
function Foo(name){
//this = {};
this.name = name;
//return this;
}
var f = new Foo("zhangsan");
2.作为对象属性执行
var obj = {
name:"A",
printName:function(){
console.log(this.name);
}
};
obj.printName();
3.作为普通函数执行(this应该是window)
function fn(){
console.log(this);// this === window
}
fn();
4.call apply bind
/**call apply **/
function fn1(name,age){
alert(name);
console.log(this);//this就是第一个参数
};
/*执行fn1这个函数,用{X:100}当this,"zhangsan"
当第一个参数*/
fn1.call({X:100},"zhangsan",20);
//会把后面的参数当数组来传递
fn1.apply({X:100},['zhangsan',20]);
/**bind**/
var fn2 = function (name,age){
alert(name);
console.log(this);
}.bind({Y:200});
//没bind之前this是window;bind之后this是{Y:100}
fn2('zhangsan',20);
eg:
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;
// this === window; this.name是undefined或者其他值
fn1();
三、作用域
1.JS没有块级作用域
2.只有函数和全局作用域
//------ 无块级作用域--------------
if(true){
var name = 'zhangsan';
}
console.log(name); //zhangsan
// 和把name在外边定义然后再if中赋值是一样的
// 推荐写法:在外边定义然后再下面赋值
var name;
if(true){
name = 'zhangsan';
}
console.log(name);
//---------- 函数和全局作用域--------------
//这个a是全局的,谁都可以获取,谁都可以改(不安全)
var a =100;
function fn(){
/*函数中定义,和外边是隔绝的,外边是改不了的;
从外边得不到,也改不了,只能从函数里去用;
防止自己的变量被污染,把所有变量都定义在一个大的函数里
*/
var a =200;
console.log('fn',a);//在函数范围内获取
}
console.log('global',a);
fn(); // global: 100; fn :200
四、作用域链
(一个自由变量一直不断的往父级作用域去找,形成一个链式结构)
-- 哪个作用域定义了这个函数,这个函数父级作用域就是谁,和函数执行没有关系
//作用域完整的使用形式、场景
1.eg:
var a =100;
function fn(){
var b =200;
//当前作用域没有定义的变量,即“自由变量”
/*函数体内没规定a是谁,但是打印a,就要向父级作用域
找a,父级作用域是全局作用域,所以a就找到var a =100;
函数父级作用域是什么,是函数定义的时候的父级作用域
,不是函数执行时候的作用域*/
console.log(a);
console.log(b);
}
fn();
2.eg:
var a =100;
function F1(){
var b =200;
function F2(){
var c = 300;
console.log(a); //100 a是自由变量
console.log(b); //200 b是自用变量
console.log(c); //300
}
F2();
}
F1();
五、闭包(作用域链的具体应用)
闭包的使用场景:
1.函数作为返回值
2.函数作为参数传递(把函数传递到另一个函数中执行)
eg:1.函数作为返回值
//F1 这个函数最终返回的是一个函数
function F1(){
/*F1作用域里面的a*/
var a =100;
/*
返回一个函数;
*/
return function(){
/*
a是自由变量,自由变量去父级作用域(F1)找;
一个函数的父级作用域,是它定义时候的作用域,
而不是执行时候的作用域
*/
console.log(a);
}
}
//把F1()赋值给f1,f1就是一个函数了
var f1 = F1();
/*是全局作用域里面的a*/
var a =200;
f1(); //100
eg:2.函数作为参数传递
function F1(){
var a =100;
//F1返回一个函数
return function(){
console.log(a);
}
}
//把F1()赋值给f1,f1就是一个函数了
var f1 = F1();
function F2(fn){
var a =200;
fn();
}
F2(f1);//100