1

1.执行上下文

  • 范围:一段<script>或者一个函数
  • 全局:变量定义、函数声明(一段<script>)
  • 函数:变量定义、函数声明、this、arguments(函数)
//变量提升:var a; function fn(name){var age; age=20; console.log(name,age);}

console.log(a);//undefined
var a = 100;

fn('zhangsan');//zhangsan 20
function fn(name){
    age = 20;
    console.log(name,age);
    var age;
}

区分函数声明和函数表达式

  • 函数声明:function fn(){}
  • 函数表达式:var fn = function(){}

2.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
  1. 作为构造函数执行
  2. 作为对象属性执行
  3. 作为普通函数执行
  4. call apply bind
// 1. 作为构造函数执行
function Foo(name){
    this.name = name;//this 是 Foo {name: "zhangsan"}
}
var f = new Foo('zhangsan');

// 2. 作为对象属性执行
var obj = {
    name : 'A',
    printName : function(){
        console.log(this.name);//this 是 {name: "A", printName: ƒ}
    }
}
obj.printName();

// 3. 作为普通函数执行
function fn(){
    console.log(this);//this === window
}
fn();

// 4. call apply  bind
function fn1(name,age){
    alert(name);
    console.log(this);//{x: 100}
}
fn1.call({x:100},'zhangsan',20);//第一个参数就是this
fn1.apply({x:100},['zhangsan',20]);//区别在于第二个参数

//.bind()必须接在函数表达式后
var fn2 = function(name,age){
    alert(name);
    console.log(this);//{y: 200}
}.bind({y:200})
fn2('zhangsan',20);

3.作用域

javascript只有函数作用域和全局作用域,没有块级作用域。

//没有块级作用域
if(true){
    var name = 'zhangsan';
}
console.log(name);//zhangsan,此处name有值

//函数作用域和全局作用域(一个script是一个全局范围)
var  a = 100;
function fn(){
    var a = 200;
    console.log('fn',a);//fn 200
}
console.log('global',a);//global 100
fn();

4.作用域链

当前作用域没有定义的变量,叫做自由变量
如果在当前作用域下没有找到定义的参数,则一级一级向上在父级作用域中查找(函数定义时的作用域中查找)。

//注意区分定义时作用域
function F1(){
    var a = 100;
    return function(){
        console.log(a);//a为自由变量,在父作用域中查找
    }
}

var f1 = F1();
var a =200;
f1();//100,注意此处为100而非200

//作用域链
var a = 100;
function fn1(){
    var b = 200;
    function fn2(){
        var c = 300;
        //当前作用域没有定义的变量,叫做自由变量
        console.log(a);//100,a为自由变量
        console.log(b);//200,b为自由变量
        console.log(c);//300
    }
    fn2();
}
fn1();

5.闭包

闭包的使用场景:

  • 1.函数作为返回值;
  • 2.函数作为参数来传递。
//1.函数作为返回值
function F1(){
    var a = 100;
    //返回一个函数
    return function(){
        console.log(a);
    }
}

var f1 = F1();

var a =200;
f1();//100

//2.函数作为参数传递
function F1(){
    var a = 100;
    //返回一个函数
    return function(){
        console.log(a);
    }
}

var f1 = F1();

function F2(fn){
    var a = 200;
    fn();
}
F2(f1);//100

6.闭包的实际应用

闭包在实际应用中主要用于封装变量,收敛权限

//函数外部不可访问_list 变量
function isFirstLoad(){
    var _list = [];//_表示私有变量
    return function(id){
        if(_list.indexOf(id) >= 0){
            return false;
        }else{
            _list.push(id);
            return true;
        }
    }    
}

var firstLoad = isFirstLoad();
firstLoad(100);//true
firstLoad(100);//false
firstLoad(200);//true
firstLoad(200);//false

7.一个面试题

题目:创建10个<a>标签,点击的时候弹出来对应的序号?

//错误写法!!!
var i,a;
for(i = 0; i < 10; i++){
    a = document.createElement('a');
    a.innerHTML = i + '<br>';
    a.addEventListener('click',function(e){
        e.preventDefault();
        alert(i);//此时点击每一个序号弹出来的都是10
    });
    document.body.appendChild(a);
}
console.log(i);//10

//正确写法
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);
}
console.log(i);//10

stefanieliang
190 声望19 粉丝

一天一笔记~


引用和评论

0 条评论