面向對象編程

這是一篇簡單介紹js面向對象的編程筆記html

一,js解析和執行編程

  js解析時,會先把var和function聲明的變量和函數放到一個詞法對象裏,變量的值是undefined,函數則是一個引用,這是js變量提高的根本機制。閉包

  若是一個變量沒有聲明就開始使用了,不論它是在局部仍是全局使用,它都是掛在了window下,是個全局變量,這點和this指向很相似,this找不到直接調用者,也是直接指向window。app

  若是變量名和函數名命名衝突了,則該命名最後指向的是函數。若是兩個函數名重複了,則後面一個函數覆蓋前面的,由於在js中,函數纔是第一等公民。dom

    e.g. 
    console.log(a)//undefined
    var a = 1
    console.log(a)//1

    e.g.
    console.log(aa)//function aa() {console.log('bbbbb')}
    var aa = 1
    function aa() {
       console.log('aaaaa')
    }
    function aa() {
       console.log('bbbbb')
    }

二,做用域函數

  js只有全局做用域和局部(函數)做用域,而且內部能夠由內到外,從近到遠,訪問即止地層層訪問外部變量,造成一條做用域鏈,而外部不能直接訪問內部變量。性能

    e.g.
    var a = 1
    var b = function() {
        var c = 2+a
        console.log(c)
    }
    b()//3
    console.log(c)//undefined

三,閉包this

  一種訪問局部變量的手段,一般指的是一個能夠訪問局部變量的函數。es5

  閉包一個是前面提到的能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中,所以要注意控制性能,提升網頁性能。spa

    e.g.
  var name = "The Window";
  var object = {
    name : "My Object",
        // 這個方法是返回了一個函數
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
    // 執行了object.getNameFunc()返回的函數,此時this找不到直接調用者,直接指向window
  alert(object.getNameFunc()());

    e.g.
  var name = "The Window";
  var object = {
    name : "My Object",
        // 這個方法是返回了一個函數
    getNameFunc : function(){
            // that指向的是object
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
    // 執行了object.getNameFunc()返回的函數,此時this固定化成了object,彈出object.name
  alert(object.getNameFunc()());

四,類與對象

  搞清楚js中的類,就須要明白三個概念:構造函數、原型對象,實例化和實例。

    e.g.
    function Person(name,age) {
        this.name = name;
        this.age = age
    }
    Person.prototype.hello = function () {
        console.log('Hello,I am '+this.name+',and I am '+this.age)
    }
    var xm = new Person('xiaoming',12)
    xm.hello()//Hello,I am xiaoming,and I am 12
    Person.prototype = {
        asset:12345
    }
    var xmm = new Person('xiaomingming',34)
    console.log(xm.asset)//undefined
    console.log(xmm.asset)//12345

其中Person函數就是構造函數,Person.prototype指向的對象就是原型對象,xm就是實例

 

  那麼在關鍵詞new的過程當中,大概發生了什麼呢?

  1,一個新對象被建立了,繼承Person.prototype原型對象裏的屬性。
  2,使用指定的參數調用構造函數Person,並將this指向新建立的對象。

  若是咱們用自定義函數模擬過程,則:

    e.g.
    function Person(name,age) {
        this.name = name;
        this.age = age
    }
    function New(f) {
        return function() {
            var o = {
                '__proto__':f.prototype
            }
            f.apply(o,arguments)
            return o
        }
    }
    var xmmm = New(Person)('xmmm',232)

  在js中,並無真正的類的概念,只是用構造函數和原型對象模擬了類,其中原型對象是類的惟一標識,當且僅當兩個對象繼承自同一個原型對象的時候,咱們才說它們是同一個類的實例。而初始化對象的構造函數則不能做爲類的標識,一般構造函數的名字被用來當作類名了而已。

  instanceof 運算符
  實例 instanceof 類名 被用來判斷一個實例是否繼承自某個原型對象,返回布爾值。

  在上述例子中,原型對象也是對象,也具備原型對象,即原型對象的原型對象,以此類推。訪問一個實例自己沒有的屬性或方法時,js會從原型對象上去找,原型對象上沒有時,會從原型對象上的原型對象上去找,......這種像鏈式同樣地繼承機制就是原型鏈,和做用域鏈很相似。

  原型對象中constructor屬性則是指向該原型對象的構造函數,在修改原型對象時,好比增刪其屬性時,可採用.符號操做,如Person.prototype.hello = s =>{console.log(s)},在實例person初始化的時候,該原型對象的constructor默認指向構造函數.

  可是若是直接給Person.prototype賦值對象型數據時,則須要顯式指定constructor屬性,不然原有的原型對象會被新對象所替代,而經過構造函數實例化的實例的__protoo__屬性都會指向最新的Person.prototype對象。在這個改動以後實例化的實例均不能繼承原有的原型對象的屬性,改動以前的實例亦不能繼承新原型對象的屬性。

  實例,構造函數,原型對象,原型鏈之間的關係能夠藉助一張神圖來講明關係

  this指針問題:

  1,老是指向方法的直接調用對象,在事件觸發中指向觸發該事件的dom節點對象

  2,指向new出來的實例

  apply和call都可以改變this指針,其區別僅僅是第二個參數的不一樣而已:

  f.call(o,a,b) === o.f(a,b) === f.apply(o,[a,b])

五,封裝

  一段代碼可以實現某種功能,隱藏該代碼的細節,僅對外開放接口去使用該功能代碼,便是對該功能代碼的封裝。

六,繼承

  繼承可使得子類具備父類的屬性和方法或者從新定義、追加屬性和方法等。具備的方式多是複製,多是引用。

  從對象層面上來看繼承:

  1,複製

        var zsh = {
            name :'zsh',
            age:23
        }
        var job = {
            job:'programer',
            language:'fe'
        }
        for (var key in job){
            zsh[key] = job[key]
        }
        console.log(zsh)//{name: "zsh", age: 23, job: "programer", language: "fe"}    

涉及到深淺複製參考:http://www.cnblogs.com/zhouxiaohouer/p/8037729.html

  2,Object.create(proto[, propertiesObject])

  es5裏的方法,注意兼容性。

  參數
  proto 新建立對象的原型對象。
  propertiesObject 可選。若是沒有指定爲 undefined,則是要添加到新建立對象的可枚舉屬性(即其自身定義的屬性,而不是其原型鏈上的枚舉屬性)對象的屬性描述符以及相應的屬性名稱。這些屬性對應Object.defineProperties()的第二個參數。
  返回值
  在指定原型對象上添加新屬性後的對象。

 

  從類的層面上來看繼承:

        // 建立父類
        // 建立子類
        // 創建聯繫,修正構造函數
        // 實例化
        function Father() {}
        function Son() {}
        Son.prototype = Object.create(Father.prototype)
        // 此時,Son.prototype.constructor指向的是function Father() {},咱們最好是將其修正過來
        Son.prototype.constructor = Son

七,多態

  '見人說人話,見鬼說鬼話。'

  根據不一樣的參數個數,調用不一樣的方法,實現不一樣的功能

  本質上是檢測arguments中數據類型來作對應的操做,將差別化的處理方式通用封裝處理。

    e.g.
    function duotai(a,b,c,d,e,f) {
        console.log(duotai.length)//返回形參個數
        console.log(arguments.length)//返回實參個數
    }
    duotai(1,2,3,4)//6 4

    e.g.
    function add() {
        var result = 0
        for (var i = 0 ;i<arguments.length-1;i++){
            result += arguments[i]
        }
        return result
    }
    add(1,2,3,4,6,7,8)//31
    add(343,567,8456,234)//9600
相關文章
相關標籤/搜索