摘要:碰過的一個有趣的問題實現一個構造函數,有一個屬性,每次調用該值加。共有方法看下面的代碼可以發現,被重復創建了如果不想方法或者屬性在每次時新創建一份,可以將其設置在構造函數的原型上。
面向對象有三個特點,一個個來說:
封裝 私有變量利用閉包實現對象的私有變量。
function Animal (age) { this.getAge = function () { return age } } var dog = new Animal(3) console.log(dog.age) // undefined console.log(dog.getAge()) // 3
碰過的一個有趣的問題:
實現一個book構造函數,有一個屬性id,每次調用該值加1。
運用閉包和立刻執行函數。
let Book = (function () { let id = 1 return function () { this.id = id++ } })() let bok1 = new Book() let bok2 = new Book() let bok3 = new Book() console.log(bok3.id) // 3共有方法
看下面的代碼可以發現,getAge被重復創建了
var dog = new Animal(3) var cat = new Animal(5) console.log(dog.getAge === dog.getAge) // false
如果不想方法或者屬性在每次new時新創建一份,可以將其設置在構造函數的原型prototype上。
Animal.prototype.feed = function () { console.log("feed") } console.log(dog.feed === cat.feed) // true繼承
聽說繼承有六種方法,假設讓Dog繼承Animal,無非就是for in 復制屬性,修改原型鏈如dog.prototype = new Animal,直接Object.create,在Dog中使用Animal.call
然而我們記住最好的一種就夠了,就是組合繼承。
先試下這樣寫,利用call的繼承:
function Animal (name) { this.name = name; this.say = function() { console.log(this.name) } } // *1 function Dog (color, name) { Animal.call(this, name) this.color = color } // *2 let wangcai = new Dog("blue", "wangcai") console.log(wangcai) // {color: "blue", name: "wangcai") wangcai.say() // "wangcal"
可是如果在*1處加上這樣的代碼
Animal.prototype.say2 = function() { console.log(this.name) }
在*3處輸入
wangcai.say2(),會報錯提示不存在該方法,說明我們的繼承是不完整的。dog沒有繼承原型鏈上的方法
我們需要在*2補上:
Dog.prototype = Object.create(Animal.prototype)
這時候不會報錯了,補上Object.create的polyfill
function objectCreate (proto) { function F() {} F.prototype = proto; return new F(); }
然而還有一點小漏洞,當我們查看wangcai.constructor時,會發現指向的是Animal。因此我們需要修復一下:
Dog.prototype.constructor = Dog
補充一下new的模擬
function fNew (base) { var o = {} o.__proto__ = base.prototype base.call(o) return o }
完整代碼
function Animal (name) { this.name = name; this.say = function() { console.log(this.name) } } Animal.prototype.say2 = function () { console.log(this.name) } function Dog (color, name) { Animal.call(this, name) this.color = color } Dog.prototype = Object.create(Animal.prototype) Dog.prototype.constructor = Dog let wangcai = new Dog("blue", "wangcai")
檢測繼承是否成功的代碼:
console.log(wangcai instanceof Animal) console.log(wangcai instanceof Dog) console.log(wangcai.constructor === Dog) console.log(wangcai.say2 === Animal.prototype.say2) console.log(wangcai.__proto__ === Dog.prototype) console.log(wangcai.__proto__.__proto__ === Animal.prototype) console.log(wangcai.__proto__.__proto__.__proto__ === Object.prototype) console.log(wangcai.constructor === Dog)
使用Object.create()和修復Dog.prototype.constructor = Dog是不是挺多余的?es6提供了這么一個函數Object.setPrototypeOf.
因此我們可以使用
Object.setPrototypeOf(Dog.prototype, Animal.prototype)
替換剛剛提到的兩行代碼
可以了解到Object.setPrototypeOf(A,B)相當于令A.__proto__ = B。
多態一個函數可以應用于不同的對象。并且根據this的不同,函數調用的結果也不同
function test() { alert([this.a, this.b]); } test.call({a: 10, b: 20}); // 10, 20 test.call({a: 100, b: 200}); // 100, 200 var a = 1; var b = 2; test(); // 1, 2
或是在函數中檢測arguments的數量和類型來實現多態
function add (a, b) { if (arguments.length === 2) { return a + b } else { return a + 1 } } console.log(add(1,4)) console.log(add(1))
END
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/95893.html
摘要:對于屬性來說類內部的調用方式靜態屬性是類的屬性普通屬性是類具體實例化出的對象的屬性所以二者是完全不同的調用方式也非常不同靜態屬性靜態屬性名類名靜態屬性名普通屬性普通屬性名類外部的調用方式靜態屬性是類的屬性普通屬性是類具體實例化出的對象的屬 對于 屬性 來說 類內部的調用方式 靜態屬性是類的屬性 普通屬性是類具體實例化出的對象的屬性 所以二者是完全不同的, 調用方式也非常不同 ...
摘要:面向對象主要知識點小結,基于構造函數可以理解為通過即將創建的對象將類實例化給一個對象賦予屬性或者方法原型便于方法的重用與構造函數模式相比,使用原型對象的好處是可以讓所有對象實例共享它所包含的屬性和方法。 JavaScript面向對象主要知識點小結,基于ECMAScript 5. 構造函數 function People(name){ //this可以理解為通過new即將創建...
摘要:參考鏈接面向對象編程模型現在的很多編程語言基本都具有面向對象的思想,比如等等,而面向對象的主要思想對象,類,繼承,封裝,多態比較容易理解,這里就不多多描述了。 前言 在我們的日常日發和學習生活中會常常遇到一些名詞,比如 命令式編程模型,聲明式編程模型,xxx語言是面向對象的等等,這個編程模型到處可見,但是始終搞不清是什么?什么語言又是什么編程模型,當你新接觸一門語言的時候,有些問題是需...
閱讀 2061·2021-11-23 09:51
閱讀 2203·2021-09-29 09:34
閱讀 3694·2021-09-22 15:50
閱讀 3556·2021-09-22 15:23
閱讀 2559·2019-08-30 15:55
閱讀 699·2019-08-30 15:53
閱讀 3066·2019-08-29 17:09
閱讀 2624·2019-08-29 13:57