Javascript 之 作用域和闭包

执行上下文

1、在一段 <script>...</script> 标签里面会有一个全局执行上下文

  变量声明、函数声明提前

2、在一个函数 function fn(arguments){...} 内部会有一个函数执行上下文

  变量声明、函数声明、 this 、 arguments 提前

函数声明: function fn () {...} 

函数表达式: var fn = function () {...} 

this            

 this 要在执行时才能确认值,定义时无法确认   js是单线程解释性语言(另一种是编译性语言),定义时不会报错,执行时才会报错

var o = {
  name: 'A',
  fn: function () {
    console.log(this.name);
  } }

o.fn();  // this === o
o.fn.call({name: 'B'});  // this === {name: 'B'}
var fn1 = o.fn;
f1();  // this === window

作为构造函数执行  this指向新创建的空对象

作为对象属性执行  this指向对象

作为普通函数执行  this指向window

 call() 、 apply() 、 bind() 

function fn (name, age) {
  alert(name);
  console.log(this);
}
fn.call({x: 100}, 'joffe');  // this === {x: 100}
fn.apply({x: 100}, ['joffe', 21]);  // this === {x: 100}

var fn = function (name, age) {
  alert(name);
  console.log(this);
}.bind({x: 200});
fn('joffe', 21);  // this === {x: 200}

 

作用域

  js没有块级作用域,只有全局作用域、函数作用域(函数内部变量,外部无法访问)

针对函数作用域

  自由变量是指在当前作用域中没有定义的变量

  在函数执行时,如果一个变量在当前函数作用域没有找到,就会去函数的父级作用域寻找(函数哪里定义,哪里就是函数的父级作用域,跟在哪里执行函数没有关系)

var a = 100;
function f1 () {
  var b = 200;
  function f2 () {
    var c = 300;
    console.log(a);  // a 是自由变量
    console.log(b);  // b 是自由变量
    console.log(c);
  }
  f2();
}
f1();

一个变量通过父级作用域一层层往上找,直到找到变量定义的作用域,这叫作用域链

实例: 创建十个 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);  // i 是一个自由变量,需要到函数父级作用域寻找
    })
    document.body.appendChild(a);
  })(i);
}

闭包

 1、函数作为返回值

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

 2、函数作为参数传递

function f1 () {
  var a = 100;
  return function (){
    console.log(a);
  }
}
var f2 = f1();
function f3 (fn){
  var a = 200;
  fn();
}
f3(f2);  // 100

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

//防止在 isFirstLoad 函数外修改 _list 的值
function isFirstLoad () {
  var _list = [];
  return function (num) {
    if(_list.indexOf(num) >= 0) {
      return false;
    } else {
      _list.push(num);
      return true;
    }
  }
}

var firstLoad = isFirstLoad();
firstLoad(10);  // true
firstLoad(10);  // false
firstLoad(20);  // true
firstLoad(20);  // false
原文地址:https://www.cnblogs.com/joffe/p/7668667.html