变量提升的理解

js语言的执行规则:先定义,后执行
变量定义、函数声明就属于定义代码的范畴(注意“函数声明”和“函数表达式”的区别)

说明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

全局环境下的this

function fn() {
    console.log(this); // this === window
}
fn();

对象方法中的this

var obj = {
    name: 'A',
    printName: function () {
        console.log(this.name); // this === obj
    }
};
obj.printName();

构造函数中的this

function Foo(name) {
    this.name = name; // this === f
}
var f = new Foo('can');

事件函数中的this

document.getElementById('div1').onclick = function () {
    console.log(this); // this === <div id="div1">div1</div> 触发当前事件的Element对象
};

call apply bind 中的this

function fn1(name, age) {
    console.log(name, age);
    console.log(this); // this === {x:100}
}

fn1.call({x: 100}, 'can', 22);
fn1.apply({x: 100}, ['can', 22]);

var fn2 = function (name, age) {
    console.log(name, age);
    console.log(this); // this === {y:200}
}.bind({y: 200});
fn2('can', 22);

创建10个a标签,点击的时候弹出来对应的序号

for (var 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); // i 是自由变量,去父作用域寻找
        });
        document.body.appendChild(a);
    })(i);
}

作用域

ES5中,无块级作用域

if (true) {
    var name = 'can';
}
console.log(name); // 'can'

函数和全局作用域

var b = 1;
function fn3() {
    var b = 2;
    console.log('fn', b); // 2
}
console.log('global', b); // 1
fn3();

自由变量

var a = 100;
function fn4() {
    var b = 200;
    // 当前作用域没有定义的变量,即“自由变量”
    console.log(a); // 100  a 是自由变量,去父作用域寻找
    console.log(b); // 200
}
fn4();
一个函数的父级作用域,是它定义时的父级作用域,而不是执行时

作用域链,即自由变量的查找

var a = 100;
function fn5() {
    var b = 200;
    function fn6() {
        var c = 300;
        console.log(a); // 100  a 是自由变量,去父作用域寻找
        console.log(b); // 200  b 是自由变量,去父作用域寻找
        console.log(c); // 300
    }
    fn6();
}
fn5();

闭包的使用场景

1.函数作为返回值

function fn1() {
    var a = 100;
    // 返回一个函数(函数作为返回值)
    return function () {
        console.log(a); // a是自由变量,去父作用域寻找
    }
}

// f1 得到一个函数
var f1 = fn1();
var a = 200;
f1(); // 100

2.函数作为参数传递

function fn1() {
    var a = 100;
    // 返回一个函数(函数作为返回值)
    return function () {
        console.log(a); // a是自由变量,去父作用域寻找
    }
}

// f1 得到一个函数
var f1 = fn1();

function fn2(fn) {
    var a = 200;
    fn();
}

fn2(f1); // 100

实际开发中闭包的应用

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

function isFirstLoad() {
    var list = [];
    return function (id) {
        if (list.indexOf(id) > -1) {
            return false;
        } else {
            list.push(id);
            return true;
        }
    }
}
// 在 isFirstLoad 函数外面,不可能修改到 list 的值
var firstLoad = isFirstLoad();
firstLoad(10); // true
firstLoad(10); // false
firstLoad(20); // true

lxcan
337 声望32 粉丝