閉包,原型鏈

閉包

在【函數定義】的時候,【函數對象】的【scope屬性】便會引用包含該函數的上一級函數在運行時所生成的【執行上下文】的【活動對象】,由於發生對象屬性之間的相互依賴,致使包含此函數的【scope屬性】所指向的活動變量,在上一級函數【執行完畢】將要【釋放執行上下文】的時候【不能釋放】其包含的【活動變量】。瀏覽器

本身的理解: 閉包的產生首先要有一個地址被引用所指向閉包

函數與對象的關係

  1. 函數就是對象的一種
  2. 對象是函數建立的

prototype原型

  1. prototype是函數的一個屬性
  2. 每個構造函數都有prototype屬性
  3. prototype的值其實是一個對象
    • 這個對象默認只有一個constructor的屬性,而且指向函數自己

構造函數中的屬性和原型中的屬性的區別

  1. 把屬性定義在原型中比定義在構造函數中消耗的內存更小,由於在內存中一個類的原型只有一個,寫在原型中的行爲能夠 被全部實例共享。實例化的時候並不會在內存中再複製一份。沒有特殊緣由,通常把屬性寫到類中,行爲寫到原型中。
  2. 使用原型的方式定義屬性,實際上不一樣對象中的屬性是共享的,也就是說對其中的任何一個對象修改了屬性,其餘對象的屬性也會跟着發生變化,由於它們指向的是同一個地址,共享同一個屬性
  3. 構造函數中定義的屬性和方法比原型中定義的屬性和方法優先級高。若是定義了同名稱的屬性和方法,構造函數中會覆蓋原型中的。

隱式原型(對象)

隱式原型:_proto_是對象中的一個屬性,每一個對象都有一個_proto_屬性,也稱爲隱式原型。而且指向建立該對象的prototype
  1. 自定義函數本質上都是經過Object函數來建立的,因此它的_proto_指向Object.prototype
  2. Object.prototype的_proto_指向null

原型鏈

原型鏈:若訪問對象屬性時,先在基本屬性中找,若是自身沒有該屬性,便會沿着_proto_這條鏈往上找。

執行上下文

在一段js代碼執行前,瀏覽器已經作了一些準備工做,其中包括對變量的聲明,變量賦值是在賦值語句執行的時候進行的。app

準備工做有三步:

  1. 變量:變量的聲明,默認賦值爲undefined
  2. this:賦值
  3. 函數聲明:賦值

這三種數據的準備狀況稱之爲「執行上下文」或者「執行上下文環境」;

函數每被調用一次,都會產生一個新的執行上下文環境,由於不一樣的調用可能會有不一樣的參數。
函數定義的時候就應經肯定了函數體內部變量的做用域

執行上下文棧

執行全局代碼時,會產生一個全局上下文環境,每次調用函數,又會產生函數上下文環境,當函數調用完成時,這個上下文環境及其中的數據都會被銷燬。再從新回到全局上下文環境。函數

處於活動狀態的執行上下文環境只有一個。(壓棧和出棧的過程)this

做用域和執行上下文

除全局做用域以外,每一個函數都會建立本身做用域。做用域在函數定義時就已經肯定了,而不是在調用時肯定。 做用域只是一個「地盤」,一個抽象的概念,其中沒有變量,要經過做用域對應的執行上下文來獲取變量的值,同一做用域下,不一樣的調用會產生不一樣的執行上下文環境,繼而產生不一樣的值。prototype

自由變量

在一個做用域中使用的變量,沒有在其中聲明(即在其餘做用域中聲明的),此時,這個變量對這個做用域來說就是自由變量(也可稱爲活動變量)code

做用域鏈

  1. 先在當前做用域查找X,若是有則獲取並結束,若是沒有則繼續;
  2. 若是當前做用域是全局做用域,則證實X未定義,結束;不然繼續;
  3. 將建立該函數的做用域做爲當前做用域;
  4. 跳轉到第一步。

繼承

  1. 對象冒充對象

    function Person(name, age) {
               this.name = name;
               this.age = age;
               this.sayName = function() {
                   console.log(this.name);
               };
           }
    
           function Student(name, age) {
               this.obj = Person;
               this.obj(name, age);
               delete this.obj;
               this.study = function() {
                   console.log("study");
               }
           }
    
           var stu1 = new Student("zhangsan", 21);
           console.log(stu1.name, stu1.age);
           stu1.sayName();
           stu1.study();
  2. 原型鏈的方式繼承

    function Person(name, age) {
       this.name = name;
       this.age = age;
       this.sayName = function () {
           console.log(this.name);
       };
    }
    function Student(name, age) {
       this.constructor(name, age);
    }
    Student.prototype = new Person();
    
    var stu1 = new Student("zhangsan", 21);
    console.log(stu1.name, stu1.age);
  3. call和apply方法內存

    function Student(name, age) {
    //            Person.call(this, name, age);
                Person.apply(this, [name, age]);
            }
    
            var stu = new Student("zhangsan", 21);
            console.log(stu.name, stu.age);
  4. 混合方式

    function Person(name, age) {
        this.name = name;
        this.age = age;
    }
    
    Person.prototype.sayName = function() {
        console.log(this.name);
    };
    
    function Student(name, age) {
        Person.call(this, name, age);
    }
    
    Student.prototype = new Person();
相關文章
相關標籤/搜索