一、原型
先從構造函數開始吧!
構造函數是什么?構造函數與其他函數唯一的區別在於調用方式不同。任何函數只要通過new來調用就可以作為構造函數,它是用來創建特定類型的對象。
下面定義一個構造函數 Female:
function Female(name){ this.name = name; this.sex = 'female'; }
通過new命令來生成一個person實例:
var person1 = new Female("Summer")
這里,構造函數Female就是實例對象person1的原型!!!Female里的this關鍵字就指的是person1這個對象!
結論:原型對象(Person.prototype)是 構造函數(Person)的一個實例。
new出來的person1對象此時已經和Female再無聯系了!也就是說每一個new出來的實例都有自己的屬性和方法的副本,
是獨立的的!修改其中一個不會影響另一個
var person1 = new Female("Summer"); var person2 = new Female("Lily"); person2.sex = 'male'; console.log(person1.sex) // female console.log(person2.sex) // male
但是,我們希望構造函數中的sex屬性是一個共有屬性,那么此時用這樣的方法,每個實例中都有一個相同的sex屬性,會造成資源極大的浪費!
那么原型對象就即將登場了!Brendan Eich決定給每一個構造函數都設置一個prototype屬性,這個屬性就指向原型對象。
其實原型對象就只是個普通對象,里面存放着所有實例對象需要共享的屬性和方法!所以,我們把需要共享的放到原型對象里,把那些不需要共享的屬性和方法存在在構造函數里!
那么上面的代碼可改寫如下:
function Person(name,age){ this.name = name; } Person.prototype.sex = 'female'; var person1 = new Person("Summer"); var person2 = new Person("Lily"); console.log(person1.sex) // female console.log(person2.sex) // female Person.prototype.sex = 'male'; console.log(person1.sex) // male console.log(person2.sex) // male
可以看出,修改prototype屬性會影響它的所有實例的sex的值!!
實例一旦創建出來就會自動引用prototype對象的屬性和方法!所以實例對象的屬性和方法一般分為兩種:一種是自身的,一種是引用自prototype的。
具體實現是這樣的:
每當代碼讀取某個對象的某個屬性的時候,都會執行一次搜索。首先從對象實例本身開始,如果在實例中找到了該屬性,則返回該屬性的值,
如果沒有找到,則順着原型鏈指針向上,到原型對象中去找,如果如果找到就返回該屬性值。
這里要提一點,如果為對象實例添加了一個屬性與原型中同名,則該屬性會屏蔽掉原型中的同名屬性,不會去修改它!
使用delete可以刪除實例中的屬性提到delete那要插一句~delete只能刪除對象下的屬性,不能刪除變量和參數!
什么是原型鏈:只要是對象就有原型, 並且原型也是對象, 因此只要定義了一個對象, 那么就可以找到他的原型, 如此反復, 就可以構成一個對象的序列, 這個結構就被稱為原型鏈
所有的實例有一個內部指針,指向它的原型對象,並且可以訪問原型對象上的所有屬性和方法。
先看JS通過原型鏈實現繼承的方法,實現 Dog 繼承 Animal 的所有屬性和方法。
復制代碼 //定義一個 Animal 構造函數,作為 Dog 的父類 function Animal () { this.superType = 'wangcai'; } Animal.prototype.speak = 'wangwang' function Dog () { this.name ='zhuzhu'; } //給Dog對象添加一個_ proto_,指向一個 Animal 實例 Dog.prototype = new Animal();
//再創建一個實例 Pig
var Pig = new Dog() //Pig繼承了Dog 和Animal的屬性
console.log(Pig.speak) //wangwang
整個 Pig 對象是這樣的