您好,登錄后才能下訂單哦!
本文實例講述了JS原型和原型鏈原理與用法。分享給大家供大家參考,具體如下:
Javascript語言的繼承機制一直很難被人理解。
它沒有"子類"和"父類"的概念,也沒有"類"(class)和"實例"(instance)的區分,全靠一種很奇特的"原型鏈"(prototype chain)模式,來實現繼承。
Brendan Eich設計javascript之初是為了實現網頁與瀏覽器之間交互的一種簡單的腳本語言
如果真的是一種簡易的腳本語言,其實不需要有"繼承"機制。但是,Javascript里面都是對象,必須有一種機制,將所有對象聯系起來。所以,Brendan Eich最后還是設計了"繼承"。
構造函數 ,是一種特殊的方法。主要用來在創建對象時初始化對象。每個構造函數都有prototype(原型)屬性
每個函數都有prototype(原型)屬性,這個屬性是一個指針,指向一個對象,這個對象的用途是包含特定類型的所有實例共享的屬性和方法,即這個原型對象是用來給實例共享屬性和方法的。
而每個實例內部都有一個指向原型對象的指針。
原型鏈
每個構造函數都有一個原型對象,原型對象都包含一個指向構造函數的指針,而實例都包含指向原型對象內部的指針。我們讓原型對象的實例(1)等于另一個原型對象(2),
此時原型對象(2)將包含一個指向原型對象(1)的指針,
再讓原型對象(2)的實例等于原型對象(3),如此層層遞進就構成了實例和原型的鏈條,這就是原型鏈的概念
構造函數
構造函數 ,是一種特殊的方法。主要用來在創建對象時初始化對象。 即為對象變量賦初始值。每個構造函數的實例都將共享構造函數的初始值。 構造函數的出現是為了解決使用Object構造函數和字面量表示法不方便創建大量重復對象的問題。
傳統創建對象實例的方法
var person={ name:'張女士', age:'80', gender:'女' }; console.log(person)
注:這個方法如果用于創建大量相同屬性和方法的對象時,會產生大量重復代碼
構造函數的方法
//構造函數方法創建對象實例 function Person(name,age,gender) { this.name=name; this.age=age; this.gender=gender; this.say=function () { alert(this.name) } } var person1=new Person('鐘女士',80,'女'); var person2=new Person('張女士',80,'女'); console.log(person2) console.log(person1)
原型模式
使用構造函數的問題是,每個方法都要在每個實例上重新創建一遍,即在構造函數的不同實例上的同名函數是不相等的。而我們創建每個構造函數都有一個prototype(原型)屬性,這個屬性是個指針,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實例共享的屬性和方法,我們使用這個原型對象來共享實例的屬性和方法的模式就叫原型模式
//原型模式創建對象 function Person(){ } Person.prototype.name='鐘女士'; Person.prototype.age=80; Person.prototype.gender='女'; var person1= new Person(); console.log(person1) //簡寫原型模式 Person.prototype={ constructor:Person name:'鐘女士', age:80, gender:'女' }
注:每個原型對象都有constructor屬性,由于簡寫模式重寫了默認的prototype對象,所以constructor也會被重新定義,不再指向他的構造函數,所以可以自己寫一個constructor屬性指向他的構造函數
原型鏈
每個構造函數都有原型對象,每個構造函數實例都包含一個指向原型對象的內部指針(proto),如果我們讓第一個構造函數的原型對象等于第二個構造函數的實例,結果第一個構造函數的原型對象將包含一個指向第二個原型對象的指針,再然第三個原型對象等于第一個構造函數的實例,這樣第三個原型對象也將包含指向第一個原型對象的指針,以此類推,就夠成了實例于原型的鏈條,這就是原型鏈的基本概念
function One(){ } function Two(){ } function Three(){ } Two.prototype=new One(); Three.prototype=new Two(); var three=new Three(); console.log(three); console.log(three.__proto__===Three.prototype) //true console.log(three.__proto__.__proto__===Two.prototype) //true console.log(three.__proto__.__proto__.__proto__===One.prototype) //true console.log(three.__proto__.__proto__.__proto__.__proto__===Object.prototype) //true
在對象實例中,訪問對象原型的方法
此屬性是瀏覽器支持的一個屬性,并不是ECMAScript里的屬性
對于不支持proto的瀏覽器,可以使用constructor,訪問到對象的構造函數,在用prototype訪問到原型
使用原型鏈解釋ANUGLAR作用域
在開發過程中,我們可能會出現控制器的嵌套,看下面這段代碼:
<div ng-controller="OuterCtrl"> <span>{{a}}</span> <div ng-controller="InnerCtrl"> <span>{{a}}</span> </div> </div> <script> function OuterCtrl($scope) { $scope.a = 1; } function InnerCtrl($scope) { } </script>
我們可以看到界面顯示了兩個1,而我們只在OuterCtrl的作用域里定義了a變量,但界面給我們的結果是,兩個a都有值,現在自控制器里的a是從父控制器里繼承過來的
我們可以父子級的作用域看成兩個原型對象,其中一個原型對象繼承另一個原型對象的實例
function Outer() { this.a = 1; } function Inner() { } var outer = new Outer(); Inner.prototype=new Outer(); var inner = new Inner(); console.log(outer.a) console.log(inner.a)
Angular的實現機制其實也就是把這兩個控制器中的$scope作了關聯,外層的作用域實例成為了內層作用域的原型。
既然作用域是通過原型來繼承的,自然也就可以推論出一些特征來。比如說這段代碼,點擊按鈕的結果是什么?
<div ng-controller="OuterCtrl"> <span>{{a}}</span> <div ng-controller="InnerCtrl"> <span>{{a}}</span> <button ng-click="a=a+1">a++</button> </div> </div> <script> function OuterCtrl($scope) { $scope.a = 1; } function InnerCtrl($scope) { } </script>
點了按鈕之后,兩個a不一致了,里面的變了,外面的沒變,這是為什么?
function Outer() { this.a = 1; } function Inner() { } var outer = new Outer(); Inner.prototype=new Outer(); var inner = new Inner(); inner.a = inner.a + 1; console.log(outer.a) console.log(inner.a)
因為在原型鏈中,訪問一個實例屬性時,會在實例本身查找,如果找不到,則搜索實例的原型,如果再搜索不到,則繼續沿著原型鏈往上查找。找到之后則會賦給該實例,所以inner上面就被賦值了一個新的a,outer里面的仍然保持原樣,這也就導致了剛才看到的結果。
上下級共享變量
比如說,我們就是想上下級共享變量,不創建新的,該怎么辦呢?
function Outer() { this.data = { a: 1 }; } function Inner() { } var outer = new Outer(); Inner.prototype = outer; var inner = new Inner(); console.log(outer.data.a); console.log(inner.data.a); inner.data.a += 1; console.log(outer.data.a); console.log(inner.data.a);
我們可以把a寫在一個對象里,當inner找到對象data并賦值到自己身上時,其實是復制了對象的指針(參考高程第4章復制引用類型和基本類型的區別),我們對對象里的屬性的改動都會反映到所有引用該對象的元素上。
反映到AngularJs,我們可以這么寫
<div ng-controller="OuterCtrl"> <span>{{data.a}}</span> <div ng-controller="InnerCtrl"> <span>{{data.a}}</span> <button ng-click="data.a=data.a+1">increase a</button> </div> </div> <script> function OuterCtrl($scope) { $scope.data = { a: 1 }; } function InnerCtrl($scope) { } </script>
這樣點擊按鈕兩個控制器的a都會+1
感興趣的朋友可以使用在線HTML/CSS/JavaScript代碼運行工具:http://tools.jb51.net/code/HtmlJsRun測試上述代碼運行效果。
更多關于JavaScript相關內容可查看本站專題:《JavaScript常用函數技巧匯總》、《javascript面向對象入門教程》、《JavaScript查找算法技巧總結》、《JavaScript錯誤與調試技巧總結》、《JavaScript數據結構與算法技巧總結》及《JavaScript數學運算用法總結》
希望本文所述對大家JavaScript程序設計有所幫助。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。