成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深入理解javascript原型和閉包

jemygraw / 2476人閱讀

摘要:深入理解原型和閉包王福朋博客園深入理解原型和閉包一切都是對(duì)象原文鏈接本文要點(diǎn)一切引用類型都是對(duì)象,對(duì)象是屬性的集合。每個(gè)對(duì)象都有一個(gè),可稱為隱式原型。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫規(guī)則約定。

深入理解javascript原型和閉包

王福朋 - 博客園 —— 《 深入理解javascript原型和閉包》

1. 一切都是對(duì)象

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3977987.html)

本文要點(diǎn)1

一切(引用類型)都是對(duì)象,對(duì)象是屬性的集合。

1. javascript 數(shù)據(jù)類型
function show(x) {

    console.log(typeof x);                  // undefined
    console.log(typeof 10);                 // number
    console.log(typeof "abc");              // string
    console.log(typeof true);               // boolean

    console.log(typeof function () {});     //function

    console.log(typeof [1, "a", true]);     //object
    console.log(typeof { a: 10, b: 20 });   //object
    console.log(typeof null);               //object
    console.log(typeof new Number(10));     //object
}

show();

值類型(不是對(duì)象):undefined, number, string, boolean

引用類型(是對(duì)象):函數(shù),數(shù)組,對(duì)象,null, new Number(10)

值類型和引用類型的類型判斷方式:

值類型的類型判斷用 typeof

引用類型的類型判斷使用 instanceof

var fn = function () {};
console.log(fn instanceof Object);  // true
2. javascript 對(duì)象

定義:若干屬性的集合(只有屬性,沒有方法,方法也是一種屬性)

var obj = {
    a: 10,
    b: function (x) {
        alert(this.a + x)
    },
    c: {
        name: "tanya",
        year: 1975
    }
}

函數(shù)也是一種對(duì)象(可以定義屬性):

var fn = function () {
    alert(100);
};

fn.a = 10;
fn.b = function () {
    alert(123);
};
fn.c = {
    name: "tanya",
    year: 1975
}

數(shù)組也是一種對(duì)象(本身就存在 length 屬性):

var arr = [1, 2, 3];
console.log(arr.length); // 3

arr.a = "tanya";
arr.b = function () {
    alert(123);
}
arr.c = {
    name: "tanya",
    year: 1975
}

for (var item in arr) {
    console.log(item) // 0 1 a b c
}
2. 函數(shù)和對(duì)象的關(guān)系

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3978035.html)

本文要點(diǎn)2

對(duì)象是通過函數(shù)創(chuàng)建的,而函數(shù)又是一種對(duì)象。

對(duì)象是通過函數(shù)創(chuàng)建的
function Fn () {
    this.name = "tanya";
    this.age = 1975;
}

var fn = new Fn(); // 說 fn 是對(duì)象,因?yàn)樗袑傩?console.log(fn.name)  // tanya
console.log(fn.age)   // 1975

通過字面量創(chuàng)建對(duì)象或數(shù)組:

var obj = { a: 10, b: 20 };
var arr = [5, "x", true];

等效于

var obj = new Object();
obj.a = 10;
obj.b = 20;

var arr = new Array();
arr[0] = 5;
arr[1] = "x";
arr[2] = true;

其中 Object 和 Array 是函數(shù):

console.log(typeof Object);  // function
console.log(typeof Array);   // function
3. prototype 原型

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3978131.html)

什么是原型?

函數(shù)都有一個(gè) prototype 屬性,它是一個(gè)對(duì)象,

函數(shù)的實(shí)例對(duì)象的 __proto__ 屬性指向該函數(shù)的 prototype 屬性,

那我們稱該對(duì)象為函數(shù)實(shí)例對(duì)象的原型

本文要點(diǎn)3

理解原型概念。

1. prototype 和 constructor 屬性

函數(shù)有一個(gè)默認(rèn)屬性 prototype,屬性值是一個(gè)對(duì)象,該對(duì)象默認(rèn)只有一個(gè) constructor 屬性,指向這個(gè)函數(shù)本身。

如上圖:SuperType 是一個(gè)函數(shù),右側(cè)的方框就是它的原型。

Object 原型里面有幾個(gè)其他屬性:

2. 在 prototype 上添加屬性
function Fn() {}
Fn.prototype.name = "tanya"
Fn.prototype.getYear = function () {
    return 1975;
};

4. 隱式原型

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3979290.html)

每個(gè)函數(shù)都有一個(gè) prototype 屬性,即原型。每個(gè)對(duì)象都有一個(gè) __proto__,可稱為隱式原型。

本文要點(diǎn)4

理解隱式原型 __proto__。

1. __proto__ 屬性

關(guān)于 __proto__ 屬性說明:是一個(gè)隱藏屬性,低版本瀏覽器不支持該屬性。

var obj = {};
console.log(obj.__proto__);
console.log(Object.prototype);
console.log(obj.__proto__ === Object.prototype);

以上代碼說明:每個(gè)對(duì)象都有一個(gè) __proto__屬性,指向創(chuàng)建該對(duì)象(這里是 obj)的函數(shù)(這里是 Object)的 prototype。

2. Object.prototype__proto__

自定義函數(shù)的 prototype:本質(zhì)和 var obj = {} 是一樣的,都是被 Object 創(chuàng)建的,所以它的 __proto__ 指向的就是 Object.prototype

Object.prototype 是一個(gè)特例——它的 __proto__ 指向的是 null。

3. 函數(shù)的 __proto__

函數(shù)也是一種對(duì)象,所以函數(shù)也有 __proto__ 屬性。至于函數(shù)的 __proto__ 是什么,還是要看函數(shù)是被誰創(chuàng)建的。

function fn(x, y) {
    return x + y;
}
console.log(fn(10, 20));  // 30

// 等價(jià)于

var fn = new Function("x", "y", "return x + y;");
console.log(fn(5, 6));  // 11

函數(shù)是被 Function 創(chuàng)建的。

上面有說過:對(duì)象的 __proto__ 指向的是創(chuàng)建它的函數(shù)的 prototype,則會(huì)有 Object.__proto__ === Function.prototype。

解釋一下:這里 Object 是一個(gè)函數(shù),被 Function 所創(chuàng)建,函數(shù)也是一種對(duì)象,所以 Object 有 __proto__ 屬性,指向創(chuàng)建它(Object)的函數(shù)(Function)的原型

上圖中,自定義函數(shù)的 Foo.__proto__ 指向 Function.prototype,Object.__proto__ 指向 Function.prototype,還有一個(gè)Function.__proto__ 指向 Function.prototype

如何理解 Function.__proto__ 指向 Function.prototype?

Function 是一個(gè)函數(shù),函數(shù)是一種對(duì)象,對(duì)象有 __proto__ 屬性。 既然是函數(shù),那么是被 Function 創(chuàng)建的,也就是 Function 是被自身創(chuàng)建的。對(duì)象的 __proto__ 指向創(chuàng)建它的函數(shù)的 prototype,所以 Function__proto__ 指向了自身的 prototype。

5. instanceof

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3979290.html)

本文要點(diǎn)5

instanceof 判定規(guī)則。

instanceof 判定

語法是 A instanceof B,A是對(duì)象,B一般是一個(gè)函數(shù)。

instanceof 判斷規(guī)則:沿著 A 的 __proto__ 這條線來找,如果能找到與 B.prototype 相等的同一個(gè)引用,即同一個(gè)對(duì)象,就返回 true。如果找到終點(diǎn)(Object.prototype.__proto__)還未重合,則返回 false。

代碼實(shí)現(xiàn):

function instance_of(L, R) { // L 表示左表達(dá)式,R 表示右表達(dá)式
    var O = R.prototype; // 取 R 的顯示原型
    L = L.__proto__; // 取 L 的隱式原型
    while (true) {
        if (L === null){
            return false;
        }
        if (O === L) { // 這里重點(diǎn):當(dāng) O 嚴(yán)格等于 L 時(shí),返回 true
            return true;
        }
        L = L.__proto__;
    }
}

根據(jù)上圖及 instanceof 判定規(guī)則理解:

console.log(Object instanceof Function);  // true
console.log(Function instanceof Object);  // true
console.log(Function instanceof Function);  // true
6. “繼承”

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3979985.html)

本文要點(diǎn)6

理解原型鏈概念

知道屬性查找方式

1. 原型鏈

javascript 中的繼承是通過原型鏈來體現(xiàn)的。

當(dāng)訪問一個(gè)對(duì)象的屬性時(shí),先在基本屬性(自身屬性)中查找,如果沒有,再沿著 __proto__ 這條鏈向上找,直到 Object.prototype.__proto__,如果還沒找到就返回 undefined,這條在原型上查找的鏈稱為原型鏈。

function Foo() {}
var f1 = new Foo();

f1.a = 10;

Foo.prototype.a = 100;
Foo.prototype.b = 200;

console.log(f1.a);  // 10
console.log(f1.b);  // 200

2. hasOwnProperty

通過 hasOwnProperty 方法可以判斷屬性是基本的(自身)還是從原型中找到的。

function Foo() {}
var f1 = new Foo();

f1.a = 10;

Foo.prototype.a = 100;
Foo.prototype.b = 200;

for (var item1 in f1) {
    if (f1.hasOwnProperty(item1)) { // 只打印自身屬性
        console.log(item1);  // a
    }
}

for (var item2 in f1) {
    console.log(item2); // a b
}

那么 hasOwnProperty 有是在哪來的呢?它是在 Objec.prototype 中定義的。

對(duì)象的原型鏈?zhǔn)茄刂?__proto__ 這條線走的,因此在查找 f1.hasOwnProperty 屬性時(shí),就會(huì)順著原型鏈一直查找到 Object.prototype。

每個(gè)函數(shù)都有 call, bind 方法,都有 length, arguments, caller 等屬性。這也是“繼承”的。函數(shù)是由 Function 函數(shù)創(chuàng)建,__proto__ 屬性指向 Function.prototype,因此繼承 Function.prototype 中的方法。

7. 原型靈活性

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3980065.html)

偶不想表^_^。

8. 簡(jiǎn)述【執(zhí)行上下文】上

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3986420.html)

本文要點(diǎn)8

理解全局執(zhí)行上下文環(huán)境。

全局執(zhí)行上下文環(huán)境

在 javascript 代碼執(zhí)行之前,瀏覽器會(huì)做一些“準(zhǔn)備工作”,其中包括對(duì)變量的聲明,而不是賦值。變量賦值是在賦值語句執(zhí)行的時(shí)候進(jìn)行的。

變量、函數(shù)表達(dá)式——變量聲明,默認(rèn)賦值為undefined;

this——賦值;

函數(shù)聲明——賦值;

這三種數(shù)據(jù)的準(zhǔn)備情況我們稱之為“執(zhí)行上下文”或者“執(zhí)行上下文環(huán)境”。

其實(shí),javascript 在執(zhí)行一個(gè)“代碼段”之前,都會(huì)進(jìn)行這些“準(zhǔn)備工作”來生成執(zhí)行上下文。這個(gè)“代碼段”分為三種情況——全局代碼、函數(shù)體、eval代碼。

為什么“代碼段”分為這三種?

代碼段就是一段文本形式的代碼。首先,全局代碼是一種,本來就是手寫文本到

其次,eval 代碼接受的也是一段文本形式的代碼。

eval("alert(123)")

最后,函數(shù)體是因?yàn)楹瘮?shù)在創(chuàng)建時(shí),本質(zhì)上是 new Function(...) 得到的,其中需要傳入一個(gè)文本形式的參數(shù)作為函數(shù)體。

function fn(x) {
    console.log(x + 5);
}

var fn = new Function("x", "console.log(x + 5)");
9. 簡(jiǎn)述【執(zhí)行上下文】下

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3987563.html)

本文要點(diǎn)9

理解執(zhí)行上下文環(huán)境

知道什么是自由變量

上下文的準(zhǔn)備工作及區(qū)別(全局與函數(shù))

1. 函數(shù)體執(zhí)行上下文環(huán)境
function fn(x) {
    console.log(arguments);  // [10]
    console.log(x);  // 10
}
fn(10);

在函數(shù)體的語句執(zhí)行之前,arguments 變量和函數(shù)參數(shù)都已經(jīng)被賦值。函數(shù)每調(diào)用一次都會(huì)產(chǎn)生一個(gè)新的執(zhí)行上下文環(huán)境,因?yàn)椴煌恼{(diào)用可能會(huì)有不同的參數(shù)。

2. 自由變量

自由變量:當(dāng)前作用域內(nèi)使用了外部作用域的變量(使用了不是在當(dāng)前作用域內(nèi)定義的變量)。

函數(shù)在定義的時(shí)候(不是調(diào)用的時(shí)候),就已經(jīng)確定了函數(shù)體內(nèi)部自由變量的作用域。

var a = 10;
function fn() {
    console.log(a); // a 是自由變量,函數(shù)創(chuàng)建時(shí),就確定了 a 要取值的作用域
}

function bar(f) {
    var a = 20;
    f(); // 打印 10, 而不是 20
}
bar(fn);
3. 上下文環(huán)境

全局代碼的上下文環(huán)境數(shù)據(jù)內(nèi)容為:

準(zhǔn)備內(nèi)容 初始化
普通變量(包括函數(shù)表達(dá)式),如: var a = 10; 聲明(默認(rèn)賦值為 undefined)
函數(shù)聲明, 如: function fn() { } 賦值
this 賦值

如果代碼段是函數(shù)體,那么需要在此(全局準(zhǔn)備內(nèi)容)基礎(chǔ)上附加:

準(zhǔn)備內(nèi)容 初始化
參數(shù) 賦值
arguments 賦值
自由變量的取值作用域 賦值

通俗執(zhí)行上下文環(huán)境定義:在執(zhí)行代碼之前,把將要用到的所有的變量都事先拿出來,有的直接賦值了,有的先用 undefined 占個(gè)空。

10. this

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3988422.html)

新增參考:http://mp.weixin.qq.com/s/xML...

本文要點(diǎn)10

掌握 this 的幾種指向問題。

函數(shù)中 this 取值是在函數(shù)被調(diào)用的時(shí)候確定的,而不是在定義時(shí)。

1. 構(gòu)造函數(shù)

所謂構(gòu)造函數(shù)就是用來 new 對(duì)象的函數(shù)。嚴(yán)格來說,所有函數(shù)都可以 new 一個(gè)對(duì)象,但是有些函數(shù)的定義不是為了作為構(gòu)造函數(shù)。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫(規(guī)則約定)。例如:Object, Array, Function 等。

function Foo() {
    this.name = "tanya";
    this.year = 1975;

    console.log(this);  // Foo { name: "tanya", year: 1975 }
}

var f1 = new Foo();
console.log(f1.name);  // tanya
console.log(f1.year);  // 1975

以上代碼中,如果函數(shù)作為構(gòu)造函數(shù)用,那么其中 this 就代表它即將 new 出來的對(duì)象, 這里 this 表示 f1。

2. 函數(shù)作為對(duì)象的一個(gè)屬性

如果函數(shù)作為對(duì)象的一個(gè)屬性時(shí),并且作為對(duì)象的一個(gè)屬性被調(diào)用時(shí),函數(shù)中的 this 指向該對(duì)象。

var obj = {
    x: 10,
    fn: function() {
        console.log(this);    //  Object { x: 10, fn: function }
        console.log(this.x);  // 10
    }
}

obj.fn();

如果 fn 函數(shù)不是作為 obj 的一個(gè)屬性被調(diào)用,會(huì)是什么結(jié)果?

var obj = {
    x: 10,
    fn: function() {
        console.log(this);    //  Window {top: Window, ...}
        console.log(this.x);  // undefined
    }
}

var fn1 = obj.fn;
fn1();

如上代碼,如果 fn 函數(shù)被賦值到了另一個(gè)變量中,并沒有作為 obj 的一個(gè)屬性被調(diào)用,那么 this 的值就是 window,this.x 為 undefined。

3. 函數(shù)用 call 或者 apply 調(diào)用

當(dāng)一個(gè)函數(shù)被 call 或 apply 調(diào)用時(shí),this 的值就取傳入的對(duì)象的值。

var obj = {
    x: 10
};

var fn = function() {
    console.log(this);  // Object {x: 10}
    console.log(this.x);
}

fn.call(obj);
4. 全局 & 普通函數(shù)調(diào)用(直接調(diào)用)

在全局環(huán)境下,this 永遠(yuǎn)是 window:

console.log(this === window);  // true

普通函數(shù)在調(diào)用時(shí),其中 this 也是 window:

var x = 10;

var fn = function() {
    console.log(this);    // Window {top: Window ...}
    console.log(this.x);  // 10
}

fn();

注意下面的情況:

var obj = {
    x: 10,
    fn: function() {
        function f() {
            console.log(this);    // Window {top: Window ...}
            console.log(this.x);  // 10
        }
        f();
    }
};

obj.fn();

雖然函數(shù) f 是在 obj.fn 內(nèi)部定義的,但它仍然是一個(gè)普通函數(shù),this 指向 window。

5. bind() 對(duì)直接調(diào)用的影響(新增)

Function.prototype.bind() 的作用是將當(dāng)前函數(shù)與指定對(duì)象綁定,并返回一個(gè)新函數(shù),這個(gè)函數(shù)無論以什么樣的方式調(diào)用,其 this 始終指向綁定的對(duì)象。

var obj = {};
function test() {
    console.log(this === obj);
}

var testObj = test.bind(obj);
test(); // false
testObj(); // true
6. 箭頭函數(shù)中的 this(新增)

箭頭函數(shù)沒有自己的 this 綁定。箭頭函數(shù)中使用的 this,指的是直接包含它的那個(gè)函數(shù)或函數(shù)表達(dá)式中的 this。

var obj = {
    test: function () {
        var arrow = () => {
            console.log(this === obj);
        }

        arrow();
    }
}

obj.test(); // true
// 這里 arrow 函數(shù)中的 this 指的是 test 函數(shù)中的 this,
// 而 test 函數(shù)中的 this 指的是 obj

另外需要注意的是,箭頭函數(shù)不能用 new 調(diào)用,不能 bind() 到某個(gè)對(duì)象(雖然 bind() 方法調(diào)用沒問題,但是不會(huì)產(chǎn)生預(yù)期效果)。不管在什么情況下使用箭頭函數(shù),它本身是沒有綁定 this 的,它用的是直接外層函數(shù)(即包含它的最近的一層函數(shù)或函數(shù)表達(dá)式)綁定的 this。

11. 執(zhí)行上下文棧

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3989357.html)

本文要點(diǎn)11

理解執(zhí)行上下文棧概念

了解壓棧、出棧過程。

1. 執(zhí)行上下文棧概念

執(zhí)行全局代碼時(shí),會(huì)產(chǎn)生一個(gè)執(zhí)行上下文環(huán)境,每次調(diào)用函數(shù)都又會(huì)產(chǎn)生執(zhí)行上下文環(huán)境。當(dāng)函數(shù)調(diào)用完成時(shí),這個(gè)上下文環(huán)境以及其中的數(shù)據(jù)都會(huì)被清除,再重新回到全局上下文環(huán)境。處于活動(dòng)狀態(tài)的執(zhí)行上下文環(huán)境只有一個(gè)。

可以把這看成是一個(gè)壓棧出棧的過程,俗稱執(zhí)行上下文棧。

藍(lán)色背景表示活動(dòng)狀態(tài)

白色背景表示非活動(dòng)狀態(tài)

2. 壓棧、出棧過程
var a = 10,                         // 1、進(jìn)入全局上下文環(huán)境
    fn,
    bar = function(x) {
        var b = 5;
        fn(x+b);// 用 B 表示        // 3、進(jìn)入 fn 函數(shù)上下文環(huán)境
    }

fn = function(y) {
    var c = 5;
    console.log(y + c);
}
// 用 A 表示
bar(10);                           // 2、進(jìn)入 bar 函數(shù)上下文環(huán)境

第一步:在代碼執(zhí)行之前,首先創(chuàng)建全局上下文環(huán)境:

全局上下文環(huán)境(全局代碼執(zhí)行前)

變量 賦值
a undefined
fn undefined
bar undefined
this window

然后是代碼執(zhí)行,執(zhí)行到 A 之前,全局上下文環(huán)境中的變量都在執(zhí)行過程中被賦值:

全局上下文環(huán)境變?yōu)?/p>

變量 賦值
a 10
fn function
bar function
this window

第二步:執(zhí)行到 A 之后,調(diào)用 bar 函數(shù)。

跳轉(zhuǎn)到 bar 函數(shù)內(nèi)部,執(zhí)行函數(shù)體語句之前,會(huì)創(chuàng)建一個(gè)新的執(zhí)行上下文環(huán)境:

bar 函數(shù)執(zhí)行上下文環(huán)境

變量 賦值
b undefined
x 10
arguments [10]]
this window

并將這個(gè)執(zhí)行上下文環(huán)境壓棧,設(shè)置為活動(dòng)狀態(tài):

第三步:執(zhí)行到 B,又調(diào)用了 fn 函數(shù),在執(zhí)行函數(shù)體語句之前,會(huì)創(chuàng)建 fn 函數(shù)的執(zhí)行上下文環(huán)境,并壓棧,設(shè)置為活動(dòng)狀態(tài):

第四步:待 B 執(zhí)行完畢,即 fn 函數(shù)執(zhí)行完畢后,此次調(diào)用 fn 所生成的上下文環(huán)境出棧,并且被銷毀(已經(jīng)用完了,就要及時(shí)銷毀,釋放內(nèi)存)。

第五步:同理,待 A 執(zhí)行完畢,即 bar 函數(shù)執(zhí)行完畢后,調(diào)用 bar 函數(shù)所生成的上下文環(huán)境出棧,并且被銷毀(已經(jīng)用完了,就要及時(shí)銷毀,釋放內(nèi)存)。

12. 簡(jiǎn)介【作用域】

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3991151.html)

參考:https://github.com/mqyqingfen...

本文要點(diǎn)12

理解作用域。

作用域

作用域是個(gè)很抽象的概念,類似于一個(gè)“地盤”。

上圖中,全局代碼和 fn 、bar 兩個(gè)函數(shù)都會(huì)形成一個(gè)作用域。

在作用域中存在上下級(jí)關(guān)系,上下級(jí)關(guān)系的確定就看函數(shù)是在哪個(gè)作用域下創(chuàng)建的。例如:fn 作用域下創(chuàng)建了 bar 函數(shù),那么 “fn 作用域” 就是 “bar 作用域” 的上級(jí)。

作用域最大的用處就是隔離變量,不同作用域下同名變量不會(huì)有沖突。例如以上代碼中,三個(gè)作用域下都聲明了“a” 這個(gè)變量,但是他們不會(huì)有沖突。各自作用域下,用各自的“a”。

13. 【作用域】和【上下文環(huán)境】

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3991995.html)

本文要點(diǎn)13

理解作用域和上下文環(huán)境。

作用域結(jié)合上下文環(huán)境

除了全局作用域外,每個(gè)函數(shù)都會(huì)創(chuàng)建自己的作用域,作用域在函數(shù)定義時(shí)就已經(jīng)確定了,而不是在函數(shù)調(diào)用時(shí)確定的。

下面按照程序執(zhí)行的順序,一步一步加上上下文環(huán)境:

第一步,在加載程序時(shí),就已經(jīng)確定了全局上下文環(huán)境,并隨著程序的執(zhí)行而對(duì)變量賦值:

第二步,程序執(zhí)行到 A ,調(diào)用 fn(10) ,此時(shí)生成此次調(diào)用 fn 函數(shù)時(shí)的上下文環(huán)境,壓棧,并將此上下文環(huán)境設(shè)置為活動(dòng)狀態(tài)。

第三步,執(zhí)行到 B 時(shí),調(diào)用 bar(100) ,生成此次調(diào)用的上下文環(huán)境,壓棧,并設(shè)置為活動(dòng)狀態(tài)。

第四步,執(zhí)行完 B ,bar(100) 調(diào)用完成。則 bar(100) 上下文環(huán)境被銷毀。接著執(zhí)行 C,調(diào)用 bar(200),則又生成 bar(200 )的上下文環(huán)境,壓棧,設(shè)置為活動(dòng)狀態(tài)。

第五步,執(zhí)行完 C ,則 bar(200) 調(diào)用結(jié)束,其上下文環(huán)境被銷毀。此時(shí)會(huì)回到 fn(10) 上下文環(huán)境,變?yōu)榛顒?dòng)狀態(tài)。

第六步,執(zhí)行完 A,fn(10) 執(zhí)行完成之后,fn(10) 上下文環(huán)境被銷毀,全局上下文環(huán)境又回到活動(dòng)狀態(tài)。

最后把以上過程連起來看看:

作用域只是一個(gè)“地盤”,一個(gè)抽象的概念,其中沒有變量,要通過作用域?qū)?yīng)的執(zhí)行上下文環(huán)境來獲取變量的值。同一個(gè)作用域下,不同的調(diào)用會(huì)產(chǎn)生不同的執(zhí)行上下文環(huán)境,繼而產(chǎn)生不同變量的值。所以,作用域中變量的值是在執(zhí)行過程中產(chǎn)生的確定的,而作用域卻是在函數(shù)創(chuàng)建時(shí)就確定了。

所以,如果要找一個(gè)作用域下某個(gè)變量的值,就需要找到這個(gè)作用域?qū)?yīng)的執(zhí)行上下文環(huán)境,再在其中尋找變量的值。

14. 從【自由變量】到【作用域鏈】

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3992795.html)

本文要點(diǎn)14

理解作用域鏈。

1. 自由變量

什么是自由變量?

在 A 作用域中使用變量 x,卻沒有在 A 作用域中聲明(在其他作用域中聲明的),對(duì)于 A 作用域來說,x就是一個(gè)自由變量。

如下:

var x = 10;

function fn() {
    var b = 20;
    console.log(x + b); // x 在這里就是一個(gè)自由變量
}

那么,在 fn 函數(shù)中,取自由變量 x 的值時(shí),要到哪個(gè)作用域中去?。俊絼?chuàng)建 fn 函數(shù)的那個(gè)作用域中取。無論 fn 函數(shù)在哪里調(diào)用。

2. 作用域鏈

作用域鏈:在當(dāng)前作用域中進(jìn)行查找,如果沒有,就在創(chuàng)建函數(shù)作用域中查找自由變量,如果沒有,就去創(chuàng)建該作用域的函數(shù)所在作用域查找,直到全局作用域?yàn)橹?。這個(gè)在作用域中查找的路線,稱之為作用域鏈。

我們拿文字總結(jié)一下取自由變量時(shí)的這個(gè)“作用域鏈”過程:(假設(shè)a是自由量)

第一步,現(xiàn)在當(dāng)前作用域查找a,如果有則獲取并結(jié)束。如果沒有則繼續(xù);

第二步,如果當(dāng)前作用域是全局作用域,則證明a未定義,結(jié)束;否則繼續(xù);

第三步,(不是全局作用域,那就是函數(shù)作用域)將創(chuàng)建該函數(shù)的作用域作為當(dāng)前作用域;

第四步,跳轉(zhuǎn)到第一步。

示例代碼:

以上代碼中:fn() 返回的是 bar 函數(shù) ,賦值給 x 。執(zhí)行 x(),即執(zhí)行 bar 函數(shù)代碼。取 b 的值時(shí),直接在 fn 作用域取出。取 a 的值時(shí),試圖在 fn 作用域取,但是取不到,只能轉(zhuǎn)向創(chuàng)建 fn 的那個(gè)作用域中去查找,結(jié)果找到了。

15. 閉包

原文鏈接:http://www.cnblogs.com/wangfupeng1988/p/3992795.html)

參考:https://stackoverflow.com/que...

本文要點(diǎn)15

知道閉包產(chǎn)生的條件及常見用法

理解閉包是什么

1. 閉包產(chǎn)生的條件

函數(shù)嵌套

內(nèi)部函數(shù)引用了外部函數(shù)的數(shù)據(jù)(可以是變量或者函數(shù))

換句話說:簡(jiǎn)單地訪問函數(shù)的詞法作用域(靜態(tài)作用域)以外的自由變量會(huì)創(chuàng)建一個(gè)閉包。

function fn () { // 外部函數(shù)
    var max = 10;

    function bar (x) { // 內(nèi)部函數(shù)
        if (x > max) { // 引用了外部函數(shù)變量 max
            console.log(x)
        }
    }
}

fn()

說明:紅色框中,收起部分為 object: { max: undefined }

那么,閉包到底是什么?

閉包是包含被內(nèi)部函數(shù)引用的在外部函數(shù)中定義的數(shù)據(jù)的對(duì)象(可以是變量或者函數(shù))。簡(jiǎn)單點(diǎn)說是:包含被引用變量(函數(shù))的對(duì)象

2. 常見的閉包

將函數(shù)作為另一個(gè)函數(shù)的返回值(函數(shù)不必為了被稱為閉包而返回,看看閉包產(chǎn)生的條件)

將函數(shù)作為實(shí)參傳遞給另一個(gè)函數(shù)調(diào)用

將函數(shù)作為另一個(gè)函數(shù)的返回值

function fn () {
    var max = 10;

    function bar () {
        return max++;
    }

    return bar; // 作為另一個(gè)函數(shù)的返回值
}

var bar = fn();
console.log(bar()); // 10
console.log(bar()); // 11
console.log(bar()); // 12

從中我們可以看出閉包的作用:

使函數(shù)內(nèi)部的變量 max 在函數(shù) fn 執(zhí)行完后,讓然存活在內(nèi)存中(其他變量已經(jīng)釋放)

讓函數(shù) fn 外部可以讀取到函數(shù)內(nèi)部的數(shù)據(jù) max(變量或者函數(shù))

也可以看出閉包的缺點(diǎn):

內(nèi)存泄漏(Memory Leak)是指程序中己動(dòng)態(tài)分配的堆內(nèi)存由于某種原因程序未釋放或無法釋放,造成系統(tǒng)內(nèi)存的浪費(fèi),導(dǎo)致程序運(yùn)行速度減慢甚至系統(tǒng)崩潰等嚴(yán)重后果。
——百度百科

函數(shù) fn 執(zhí)行完之后,被函數(shù) bar 引用的變量沒有釋放,占用內(nèi)存時(shí)間會(huì)變長

可能造成內(nèi)存泄漏(memory leaks)

那對(duì)應(yīng)的解決方案是:

只需要在不使用函數(shù)時(shí),置空就行了 bar = null;

將函數(shù)作為實(shí)參傳遞給另一個(gè)函數(shù)調(diào)用

function fn () {
    var max = 1;
    var interval;
    interval = setInterval(function () { // 將匿名函數(shù)作為 setInterval 函數(shù)的參數(shù)調(diào)用
        if (max > 100) clearInterval(interval)
        console.log(max++);
    }, 1000)
}

fn();

注意圖中 Closure (fn),fn 指的是查找引用變量時(shí)的作用域。

3. 閉包作用域

代碼一

function fn () { // Closure (fn) { x: 1 }
    var x = 1;
    function foo () { // Closure (foo) { y: 2 }
        var y = 2;
        console.log(x + y)
        return function bar () {
            var z = 3;
            console.log(x + y + z)
        }
    }
}

var foo = fn();
var bar = foo();
bar();

從上圖中可以看到,閉包所在作用域平行于引用變量(x, y)所在的作用域。

代碼二(繼續(xù)說明閉包所在作用域)

function fn () {
    var x = 1;
    function foo () {
        console.log(x++);
    }

    function bar () {
        console.log(x++);
    }

    return {
        foo: foo,
        bar: bar
    }
}

var o = fn();
var foo = o.foo;
var bar = o.bar;

foo(); // x: 1
bar(); // x: 2

從代碼輸出可以看到,閉包并不是屬于某一個(gè)內(nèi)部函數(shù),也恰好印證了上面說的。

16. 總結(jié) 文章說明

感謝王福朋

內(nèi)容絕大部分來自王福朋 - 博客園 —— 《 深入理解javascript原型和閉包
》,我只是重畫了大部分的圖和對(duì)少量內(nèi)容進(jìn)行了補(bǔ)充(比如:this 章節(jié)的“新增”、閉包部分)

文章初衷

希望在一篇文章中進(jìn)行概括說明這些內(nèi)容(并不是說分開不好),只是這樣讀起來更加順暢,找起來比較方便(離線也可以哦,已上傳到 Github上,歡迎 star、fork);

自己也可以針對(duì)相關(guān)內(nèi)容進(jìn)行擴(kuò)充(不用看到一些額外的相關(guān)知識(shí)就收藏一個(gè)網(wǎng)址^_^,你也可以把這篇文章轉(zhuǎn)到你的賬號(hào)下,進(jìn)行擴(kuò)充,說明來源即可);

文章反饋

如有錯(cuò)誤,歡迎指出;

如有疑問,歡迎討論;

文章后續(xù)

如果看到相關(guān)的新的知識(shí),會(huì)添加到對(duì)應(yīng)主題下面(以“新增”標(biāo)明);

如果你看到這里沒有提到的相關(guān)內(nèi)容,也可以給我鏈接,我會(huì)進(jìn)行補(bǔ)充,并貼上你的大名;

撒花,待續(xù),期待你們的加入……

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92385.html

相關(guān)文章

  • JavaScript深入淺出

    摘要:理解的函數(shù)基礎(chǔ)要搞好深入淺出原型使用原型模型,雖然這經(jīng)常被當(dāng)作缺點(diǎn)提及,但是只要善于運(yùn)用,其實(shí)基于原型的繼承模型比傳統(tǒng)的類繼承還要強(qiáng)大。中文指南基本操作指南二繼續(xù)熟悉的幾對(duì)方法,包括,,。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處。 怎樣使用 this 因?yàn)楸救藢儆趥吻岸?,因此文中只看懂?8 成左右,希望能夠給大家?guī)韼椭?...(據(jù)說是阿里的前端妹子寫的) this 的值到底...

    blair 評(píng)論0 收藏0
  • 深入理解JavaScript,這一篇就夠了

    摘要:也就是說,所有的函數(shù)和構(gòu)造函數(shù)都是由生成,包括本身。如果只考慮構(gòu)造函數(shù)和及其關(guān)聯(lián)的原型對(duì)象,在不解決懸念的情況下,圖形是這樣的可以看到,每一個(gè)構(gòu)造函數(shù)和它關(guān)聯(lián)的原型對(duì)象構(gòu)成一個(gè)環(huán),而且每一個(gè)構(gòu)造函數(shù)的屬性無所指。 前言  JavaScript 是我接觸到的第二門編程語言,第一門是 C 語言。然后才是 C++、Java 還有其它一些什么。所以我對(duì) JavaScript 是非常有感情的,畢...

    villainhr 評(píng)論0 收藏0
  • 深入理解javascript原型閉包

    摘要:情況構(gòu)造函數(shù)所謂構(gòu)造函數(shù)就是用來對(duì)象的函數(shù)。另外注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫規(guī)則約定。閉包但是你只需要知道應(yīng)用的兩種情況即可函數(shù)作為返回值,函數(shù)作為參數(shù)傳遞。如上代碼,函數(shù)作為返回值,賦值給變量。這就是需要理解閉包的核心內(nèi)容。 原文鏈接http://www.cnblogs.com/wangfupeng1988/p/3977924.html 對(duì)象是屬性的集合。 function ...

    _ang 評(píng)論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

    rottengeek 評(píng)論0 收藏0
  • 深入理解JavaScript原型閉包

    摘要:本文是本人閱讀學(xué)習(xí)深入理解原型和閉包時(shí)所作的總結(jié)和筆記,當(dāng)然也引用了很多原文,感興趣的朋友也可以直接去看原文。即這里的稱為隱式原型。注意,構(gòu)造函數(shù)的函數(shù)名第一個(gè)字母大寫規(guī)則約定。但實(shí)際上,上述情況是一種理想的情況。 本文是本人閱讀學(xué)習(xí)深入理解JavaScript原型和閉包時(shí)所作的總結(jié)和筆記,當(dāng)然也引用了很多原文,感興趣的朋友也可以直接去看原文。 1、一切都是對(duì)象 先說結(jié)論,一切引用類型...

    missonce 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<