做用域鏈、閉包和原型鏈

Function:  匿名函數,做用域,做用域鏈和閉包html

函數的重載:  什麼是:函數名相同,參數列表不一樣.根據傳入函數的參數的不一樣,整形不一樣的邏輯.  數組

什麼時候用:若是一項任務,根據不一樣的參數,不執行不用的邏輯.  瀏覽器

優勢:減輕調用者的負擔.  問題:js語法不知函數的重載.閉包

 解決辦法:在函數中都有arguments的屬性,專門用於接收傳入函數的全部參數值的類數組對象.app

匿名函數:  什麼是:在函數定義時,不給函數名,即不被任何變量引用.  函數

什麼時候用:肯定函數只使用一次.  優勢:節約內存.  this

如何用:1.自調()--定義完當即執行.;2回調()--定之後,傳給其餘函數使用;prototype

做用域:  什麼是:變量的有效範圍.htm

 函數的生命週期(四個部分):對象

   1.程序開始執行    執行環境棧-Execution Context Stack:專門按順序保存每一個函數的執行環境的集合.    全局EC:開始執行程序時,首先將全局EC壓入ECS中.    建立window對象,保存全部全局函數和變量.window其實就是全局做用域.  

  2.函數聲明時    建立函數對象,封裝函數定義.    用函數名建立一個變量,引用函數對象.    在函數中添加scope屬性,用來引用函數來自的做用域對象.

  3.函數調用時    建立活動對象:Active Object.專門用來保存調用函數時的中局部變量.    AO其實就是函數做用域對象;    AO中的parent屬性會引用函數來自的父級做用域對象.由此便造成了做用域鏈.    做用域鏈控制着變量的使用順序,局部優先,而後是全局變量.    在再ECS中壓入函數的執行環境.而且有屬性scope chain 引用了AO

  4.函數調用後    函數的執行環境彈棧,則AO伴隨着引用消失而消失,則局部變量也跟着消失. 閉包  什麼是:能保證局部變量的重用,又能保護其不受污染.

 什麼時候用:但願一個變量.......  

怎麼用:3步   

  1.使用外層函數將局部變量和內層函數包裹起來.   2.外層函數將內層函數對象返回.   3.調用外層函數得到返回的內層函數對象.  筆試時,通常先找出受保護的局部變量並計算出其最後的值.而後找到引用這個變量的函數.要注意函數只有被調用時,纔會執行.

判斷是不是自有屬性:obj.hasOwnProperty("屬性名");

回顧:面向對象  三大特色:  

  封裝:將一個事物的屬性和功能集中定義在一個對象中.  

  繼承:父對象的成員,子對象無需建立,就可以使用;   即重用了代碼,又節省了內存.

   多態-重寫:同一種方法在不一樣的狀況下表現出不一樣的狀態.

  1.建立對象--封裝(3種方法--前兩種用於建立單獨的對象)  var obj={屬性名:屬性值,...,方法名:function(){}};  var obj={};(new和()都能省略,但不能同時省略)obj[屬性名]="屬性值";  定義構造函數;var obj=new 構造函數(屬性值,...);

   js底層,一切對象都是hash數組. 訪問本身的屬性:this.屬性名;  

  new作了4件事   

   1.建立了一個空的對象;  

   2.設置新對象的_porto_屬性繼承構造函數的原型對象.

   3.用新對象調用構造函數對象,將構造函數的this臨時替換成新對象.

   4.將生成的新對象的地址返回給變量. 2.調用對象的方法,操做對象的屬性  

原型對象:prototype  是集中保存父級對象的共有成員的對象.  

  如何得到:構造函數.prototype   子對象._proto_;   其中,子對象的_proto_屬性是內部屬性,沒法直接得到.   Object.getPrototypeOf(obj);   獲取obj對象的父級原型對象. 判斷自有屬性和共有屬性:  自有屬性是指保存在子對象本地的成員,保存在父級原型對象中的是共有屬性.  obj.hasOwnPrototype("屬性名");    

  判斷obj是否包含自有屬性.(false並不能表示這個屬性就是共有屬性,還多是沒有)  共有屬性:在以前的基礎上,obj.屬性名!=undefined;此時表示爲共有屬性. 內置對象的API瀏覽器兼容性問題:  內置對象的API都存儲在其原型對象中,若是不支持該方法就能夠直接在其原型對象中添加該方法便可,重要的是該方法的實現原理. 判斷繼承關係:  根據原型對象判斷:  father.isPrototypeOf(child);  判斷father是不是child的父級對象,同時也表示child是不是father的子對象.  根據構造函數判斷:  child instancof 構造函數  判斷child是不是構造函數創造出來的對象.

  筆試題:判斷一個對象是不是數組類型,有幾種方法.(4種)

  1.Array.prototype.isPrototypeOf(xxx);//根據原型判斷  

  2.xxx instanceof Array;//根據構造函數判斷  

  3.根據對象的class屬性判斷.   其中,只有Object的直接子類對象能夠直接調用xxx.toString();方法來獲取class的值.其餘的子類對象的toString()方法都被重寫了.如何解決呢?--call     

call強行調用函數,而且臨時替換爲this對象.(強行借用一個本沒法調用到的函數.)  Object.prototype.toString.call(obj)--返回"[object Array]"  因此在判斷一個對象是否爲數組時,  判斷Object.prototype.toString.call(obj)==="[object Array]"     

   4.ES5之後支持Array.isArray(obj);--其底層所示用的原理仍是使用的第三種方法. 做用域鏈和原型鏈:  做用域鏈是js默認執行的路線,同時也是控制變量的執行順序.  而原型鏈則是控制js中對象的屬性的執行循序.

面向對象中多個類型間若是有相同結構的屬性和方法,則須要抽象到父類型中. 例如:都有name屬性和fly方法.那麼就能夠抽象到父類中. 那麼此時,在子類對象的建立過程當中碰見問題.  首先是子類對象在建立時怎麼調用父類的構造方法?(這裏使有call和apply方法,做用都是強行調用一個函數.並將this改成當前正在建立的新對象.不一樣的是,call須要單獨將參數寫出,而apply只用使用arguments就能夠,注意參數的先後順序.)  而後是子類對象怎麼得到父類對象的的方法?繼承.經過方法   Object.setPrototypeOf(子類對象.prototype,父類對象.prototype);

修改繼承:  修改繼承只有3種方法

   1.修改一個對象的父對象.--就是改變__proto__屬性  child.__proto__=father=>Object.setPrototypeOf(child,father);  

  2.批量修改全部子對象的父對象--就是修改構造函數的prototype.  構造函數.prototype=father(強調必須在開始建立對象前修改)  

  3.兩種類型間的繼承       若是多個對象,擁有相同的屬性結構和功能,那麼就能夠抽象出一個公共的父對象中  

  怎麼作:  3.1 定義公共父類型,來集中定義共有的屬性和功能.  

      3.2 讓子類的原型對象繼承父類的原型對象(目的是讓子類可使用父類中的共有方法)--inherits(繼承):直接使用父對象中的成員--必須繼承才能使用公共方法.    Object.setPrototypeOf(子類型構造函數.prototype,父類型構造函數.prototype);

      3.3 在子類構造函數中借用父類型構造函數--(extends)擴展:爲子對象擴展父類沒有的屬性.  父類型構造函數.call(this,屬性參數);  父類型構造函數.apply(this,arguments);  call與apply的區別--同:都是強行調用一個函數,將this改成當前正在調用的對象      異:call每一個參數必須獨立傳入,apply全部參數放在一個集合中集中傳入(argument)

ES5新特性:  對象的屬性:兩大類-命名屬性和內部屬性(不可直接修改)  

  命名屬性(自定義屬性):  數據屬性:實際存儲屬性值的屬性(就是一般咱們所寫的.)   四大特性:   value,wirtable,enumerable,configurable.(默認值都爲true)   如何產看四大特性:   Object.getOwnpropertyDescriptor(obj,"屬性名")   如何設置四大特性:   Object.defineProperty(obj,屬性名,{//一次修改一個     特性:值,...    });   Object.defineProperties(obj,{//一次修改多個.    屬性名:{     特性:值,...    }   })  訪問器屬性(爲了保護屬性-一般須要定義的):--爲了自定義保護的邏輯.   四大特性:   get:function(){    return 受保護的屬性值;   }   set:function(val){    //驗證經過    受保護屬性值=val;   }   enumerable,configurable.  什麼時候使用:對一個屬性自定義保護邏輯時.  如何使用:Object.defineProperty(   obj,"屬性名",{    get:function(){return 屬性值},//js自動調用    set:function(val){//驗證 賦值}//js自動調用   }  ) 筆試題:在js中定義一個類型,包含共有屬性和私有屬性.  js中的私有屬性其實就是一個受閉包保護的一個局部變量.(注意,兩者必須相互配合使用才能造成私有屬性) ***注意:爲一個已定義好的對象添加私有屬性,使用添加外層函數的閉包結構(匿名函數的自調)  爲多個子類對象添加相同的私有屬性.則對構造函數設置一個受閉包保護的一個局部變量.(其中,構造函數就一個外部函數,因此不用再定義.)

防篡改:防止對已經建立好的對象的屬性進行增減. 三個級別:  

  1.防擴展:禁止向對象中添加新屬性\  每一個對象中都有一個extensible屬性,控制可否向變量中添加新屬性,默認爲true.  Object.preventExtension(obj);//設置對象中的extensible屬性爲false  問題,不妨刪除.      

  2.密封:即防擴展,又防刪除(是經過設置每一個屬性的configurable爲false實現的).  Object.seal(obj);  

  3.凍結:全部屬性禁止增減,同時也禁止修改.  

    Object.freeze(obj); Object.create():  什麼時候:經過一個(父)對象建立一個子對象時使用.  筆試題:寫一個函數,模擬create方法的實現過程  

     3步:1.基於現有父對象建立一個新的子對象;      

    2.繼承父對象      

    3.同時擴展子對象的自有屬性.   --用Object,defineProperties(obj,    屬性:{}   );

      注意: 原型方法/實例方法: 必須用具體對象才能調用  構造函數方法: 不須要任何具體對象便可直接調用       

ES5-數組API  判斷數組中全部元素,是否符合要求:  every:判斷每一個元素是否都符合要求.  arr.every(function(val,idx,arr){   //回調函數用於檢測每一個函數   //val;自動得到當前元素值   //idx:自動得到當前元素的位置   //arr:自動得到當前正在遍歷的數組  })  some:判斷是否包含知足要求的元素.  遍歷:  forEach:對原數組中的每一個元素執行相同的操做.  arr.forEach(function(val,idx,arr){   //對arr[idx]的值作出修改  })  map:將原數組中的每一個元素加工後,生成新數組.  arr.map(function(...){   //根據條件   return 新值;  })  過濾和彙總  filter:複製出原數組中符合要求的元素,組成新元素.  var newarr=arr.filter(function(...){...})  reduce:將數組中每一個元素的值彙總出一個結果.

 bind:基於現有函數,建立一個新函數,提早永久綁定函數中的this爲指定對象.  

筆試題----模擬實現bind方法    call與apply與bind:  call,apply:強行借用一個函數,並臨時替換函數中的this爲指定對象.  call與apply是執行一個函數.  bind:建立一個新函數,並永久綁定this和部分屬性.  bind不是執行函數,而是建立一個函數

 

將類數組對象轉爲純數組:  var new=[](或者Array.prototype).slice.call(arguments);

須要手寫的函數:forEach,map,create,bind(請看下面的連接)

http://www.cnblogs.com/tianzun-blog/p/5966401.html

相關文章
相關標籤/搜索