背景介紹
1.構(gòu)造函數(shù)
構(gòu)造函數(shù) ,是一種特殊的方法。主要用來在創(chuàng)建對象時初始化對象。每個構(gòu)造函數(shù)都有prototype(原型)屬性
2.原型模式
每個函數(shù)都有prototype(原型)屬性,這個屬性是一個指針,指向一個對象费什,這個對象的用途是包含特定類型的所有實(shí)例共享的屬性和方法,即這個原型對象是用來給實(shí)例共享屬性和方法的手素。
而每個實(shí)例內(nèi)部都有一個指向原型對象的指針鸳址。
原型鏈
每個構(gòu)造函數(shù)都有一個原型對象,原型對象都包含一個指向構(gòu)造函數(shù)的指針泉懦,而實(shí)例都包含指向原型對象內(nèi)部的指針稿黍。我們讓原型對象的實(shí)例(1)等于另一個原型對象(2),
此時原型對象(2)將包含一個指向原型對象(1)的指針,
再讓原型對象(2)的實(shí)例等于原型對象(3)祠斧,如此層層遞進(jìn)就構(gòu)成了實(shí)例和原型的鏈條闻察,這就是原型鏈的概念
構(gòu)造函數(shù)
構(gòu)造函數(shù) ,是一種特殊的方法琢锋。主要用來在創(chuàng)建對象時初始化對象辕漂。 即為對象變量賦初始值。每個構(gòu)造函數(shù)的實(shí)例都將共享構(gòu)造函數(shù)的初始值吴超。 構(gòu)造函數(shù)的出現(xiàn)是為了解決使用Object構(gòu)造函數(shù)和字面量表示法不方便創(chuàng)建大量重復(fù)對象的問題钉嘹。
傳統(tǒng)創(chuàng)建對象實(shí)例的方法
? var person={
? ? ? name:'張女士',
? ? ? age:'80',
? ? ? gender:'女'
? };
console.log(person)
注:這個方法如果用于創(chuàng)建大量相同屬性和方法的對象時,會產(chǎn)生大量重復(fù)代碼
構(gòu)造函數(shù)的方法
? ? //構(gòu)造函數(shù)方法創(chuàng)建對象實(shí)例
? ? 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)
原型模式
使用構(gòu)造函數(shù)的問題是鲸阻,每個方法都要在每個實(shí)例上重新創(chuàng)建一遍跋涣,即在構(gòu)造函數(shù)的不同實(shí)例上的同名函數(shù)是不相等的。而我們創(chuàng)建每個構(gòu)造函數(shù)都有一個prototype(原型)屬性鸟悴,這個屬性是個指針陈辱,指向一個對象,而這個對象的用途是包含可以由特定類型的所有實(shí)例共享的屬性和方法细诸,我們使用這個原型對象來共享實(shí)例的屬性和方法的模式就叫原型模式
? //原型模式創(chuàng)建對象
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屬性,由于簡寫模式重寫了默認(rèn)的prototype對象震贵,所以constructor也會被重新定義利赋,不再指向他的構(gòu)造函數(shù),所以可以自己寫一個constructor屬性指向他的構(gòu)造函數(shù)
原型鏈
每個構(gòu)造函數(shù)都有原型對象猩系,每個構(gòu)造函數(shù)實(shí)例都包含一個指向原型對象的內(nèi)部指針(proto)媚送,如果我們讓第一個構(gòu)造函數(shù)的原型對象等于第二個構(gòu)造函數(shù)的實(shí)例,結(jié)果第一個構(gòu)造函數(shù)的原型對象將包含一個指向第二個原型對象的指針寇甸,再然第三個原型對象等于第一個構(gòu)造函數(shù)的實(shí)例塘偎,這樣第三個原型對象也將包含指向第一個原型對象的指針疗涉,以此類推,就夠成了實(shí)例于原型的鏈條吟秩,這就是原型鏈的基本概念
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
在對象實(shí)例中博敬,訪問對象原型的方法
1、使用proto屬性
此屬性是瀏覽器支持的一個屬性峰尝,并不是ECMAScript里的屬性
2.Object.getPrototypeOf
3.使用constructor.prototype的方法
對于不支持proto的瀏覽器,可以使用constructor收恢,訪問到對象的構(gòu)造函數(shù)武学,在用prototype訪問到原型
使用原型鏈解釋ANUGLAR作用域
在開發(fā)過程中,我們可能會出現(xiàn)控制器的嵌套伦意,看下面這段代碼:
? ? <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變量,但界面給我們的結(jié)果是驮肉,兩個a都有值,現(xiàn)在自控制器里的a是從父控制器里繼承過來的
我們可以父子級的作用域看成兩個原型對象熏矿,其中一個原型對象繼承另一個原型對象的實(shí)例
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的實(shí)現(xiàn)機(jī)制其實(shí)也就是把這兩個控制器中的$scope作了關(guān)聯(lián),外層的作用域?qū)嵗蔀榱藘?nèi)層作用域的原型离钝。
既然作用域是通過原型來繼承的票编,自然也就可以推論出一些特征來。比如說這段代碼卵渴,點(diǎn)擊按鈕的結(jié)果是什么慧域?
<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>
點(diǎn)了按鈕之后,兩個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)
因?yàn)樵谠玩溨谢ザL問一個實(shí)例屬性時,會在實(shí)例本身查找痘拆,如果找不到仰禽,則搜索實(shí)例的原型,如果再搜索不到错负,則繼續(xù)沿著原型鏈往上查找坟瓢。找到之后則會賦給該實(shí)例踊兜,所以inner上面就被賦值了一個新的a纬乍,outer里面的仍然保持原樣,這也就導(dǎo)致了剛才看到的結(jié)果斤寂。
上下級共享變量
比如說识颊,我們就是想上下級共享變量诚镰,不創(chuàng)建新的奕坟,該怎么辦呢?
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(bǔ)寫在一個對象里清笨,當(dāng)inner找到對象data并賦值到自己身上時月杉,其實(shí)是復(fù)制了對象的指針(參考高程第4章復(fù)制引用類型和基本類型的區(qū)別),我們對對象里的屬性的改動都會反映到所有引用該對象的元素上抠艾。
反映到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>
這樣點(diǎn)擊按鈕兩個控制器的a都會+1
---------------------
原文:https://blog.csdn.net/qq_42019025/article/details/80708446