JavaScript变量声明、变量作用域、作用域链、函数、闭包、

2018-04-26  本文已影响15人  10xjzheng

摘自《JavaScript权威指南(第六版)》

1. 变量声明

scope='global';
function checkscope2() {
    scope='local';
    myscope='local';
    return [scope,myscope];
}
console.log(myscope); //  输出 undefined 此时未解析
console.log(checkscope2()); // 输出 ["local", "local"]
scope;// 输出 local
console.log(myscope); //  local 

2. 变量作用域

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f();
}
checkscope(); //输出local scope
/**
** 代码中在不同位置定义了变量i,j和k,它们都在同一个作用域内——这三个变量在函数体内均是有定义的。
这意味着变量在声明之前甚至已经可用。JavaScript这个特性被非正式地称为声明提前。
**/
function test(o) {
    var i=o;
    if(typeof(o) == 'object') {
        var j = o;
        for(var k=0; k<10; k++) {
            console.log(k);
        }
    }
    console.log(j);
}
/**
* 输出是undefined, 变量存在但未赋值
**/
function f() {
    var scope;
    console.log(scope);
    scope = "local";
    console.log(scope);
}
var truevar = 1; //声明一个不可删除的全局变量
fakevar = 2; //创建全局对象 的一个可删除的属性
this.fakevar2 = 3; // 同上
delete truevar; //  => false 变量并没有被删除
delete fakevar(2); // => true 变量被删除

JavaScript全局变量是全局对象的属性,这是ECMAScript规范中强制规定的,对于局部变量则没有如此规定,局部变量当做跟函数调用相关的某个对象的属性。ECMAScript 3 规范称该对象为“调用对象”,ECMAScript 5 规定称为“声明上下文对象”。JavaScript可以允许this关键字来引用全局对象,却没有办法可以引用局部变量中存放的对象。这种存放局部变量的对象的特有性质,是一种对我们不可见的内部实现。

3. 作用域链

4. 函数和闭包

理解闭包首先要了解嵌套函数的词法作用域规则:

/**
* JavaScript函数的执行用到了作用域链,这个作用域链是函数定义的时候创建的。
嵌套的函数f()定义在这个作用域链里,其中的变量scope一定是局部变量,不论
何时何地执行f(),这种绑定在执行f()时依然有效。因此最后一行代码返回的是“local”。闭包能够捕捉到局部变量和参数,并一直保存下来,看起来想这些
变量绑定到了在其中定义它们的外部函数。
**/
var scope = 'global';
function checkscope() {
    var scope = "local";
    function f(){return scope;}
    return f;
}
checkscope()(); //输出local
/** 
* 代码定义了一个立即调用的函数,返回值也是函数,嵌套的函数可以访问
* 外部函数的counter变量。但外部函数返回之后,其它任何代码无法访问counter
* 只有内部函数能够访问它。如果有多个嵌套函数,也可以访问它,这多个嵌套函* 数共享一个作用域链。
**/
var uniqueInteger = (function() {
      var counter = 0; 
      return function() { return counter++; };
}());
uniqueInteger(); // 0 
uniqueInteger(); // 1


/**
*  每次调用counter()都会创建一个新的作用域和一个新的私有变量。因此,如果
* 调用counter()两次,则会得到两个计数器对象,而且彼此包含不同的私有变量。
**/
function counter() {
      var n = 0;
      return {
              count: function() { return n++; },
              reset: function() { n = 0; }
      };
}
var c = counter(), d = counter(); //创建两个计数器
c.count();  // => 0;
d.count(); // => 0 它们互不干扰
c.reset(); // reset() 和 count() 方法共享状态
c.count(); // => 0 因为我们重置了c
d.count(); // => 1 没有重置d
var self = this;

5. 原型和原型链

5.1 原型
function Person() {

}
// 虽然写在注释里,但是你要注意:
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.name) // Kevin

console.log(person.__proto__ === Person.prototype); // true
console.log(Person === Person.prototype.constructor); // true
// 顺便学习一个ES5的方法,可以获得对象的原型
console.log(Object.getPrototypeOf(person) === Person.prototype) // true
image.png
5.2 原型链
image.png
上一篇 下一篇

猜你喜欢

热点阅读