原型鏈其實就是有限的實例物件和原型之間組成有限鏈,就是用來實現共享屬性和繼承的。存在兩個主要的問題:1、它不方便給父級類型傳遞參數;2、父級類型當中的引用類型被所有的實例共享。
本教學操作環境:windows7系統、javascript1.8.5版、Dell G3電腦。
new操作符具體做了什麼呢?其實很簡單,就乾了三件事情。
var obj = {}; obj.__proto__ = Base.prototype; Base.call(obj);
第一行,我們建立了一個空物件obj
第二行,我們將這個空物件的__proto__成員指向了Base函數物件prototype成員物件
第三行,我們將Base函數物件的this指標替換成obj,然後再呼叫Base函數,於是我們就給obj物件賦值了一個id成員變量,這個成員變數的值是」base”,關於call函數的用法。
在談原型鏈之前,我們首先要了解自訂函數與 Function 之間是什麼關係,而建構子、原型和實例之間又有什麼千絲萬縷的關係呢?其實,所有的函數都是 Function 的實例。在建構子上都有一個原型屬性prototype,該屬性也是一個物件;那麼在原型物件上有一個constructor 屬性,該屬性指向的就是建構子;而實例物件上有一個_proto_ 屬性,該屬性也指向原型對象,且該屬性不是標準屬性,不可以用在程式設計中,該屬性用於瀏覽器內部使用。
// _proto_ 在函数里有一个属性prototype 由该函数创建的对象默认会连接到该属性上 //prototype 与 _proto_ 的关系 _proto_是站在对象角度来说的 prototype 是站在构造函数角度来说的
下面,我們來看圖說話。
1、構造函數、原型和實例之間的關係
① Object
② Function Object Array
了解這些之後,我們再來討論什麼是原型鏈。說穿了,其實就是有限的實例物件和原型之間組成有限鏈,就是用來實現共享屬性和繼承的。下面,我們看程式碼說話。
var obj = new Object(); 对象是有原型对象的 原型对象也有原型对象 obj._proto_._proto_._proto_ 原型对象也有原型对象,对象的原型对象一直往上找,会找到一个null // 原型链示例 var arr = []; arr -> Array.prototype ->Object.prototype -> null var o = new Object(); o -> Object.prototype -> null;
function Foo1(){ this.name1 = '1'; } function Foo2(){ this.name2 = '2'; } Foo2.prototype = new Foo1(); function Foo3(){ this.name = '3'; } Foo3.prototype = new Foo2(); var foo3 = new Foo3(); console.dir(foo3);
接下來就是繼承問題了。
function Animal(name){ this.name = name; } function Tiger(color){ this.color = color; } // var tiger = new Tiger('yellow'); // console.log(tiger.color); // console.log(tiger.name); //undefined // Tiger.prototype = new Animal('老虎'); //一种方式 Object.prototype.name = '大老虎'; //第二种方式 var tiger = new Tiger('yellow'); console.log(tiger.color); console.log(tiger.name);
值得注意的是,這裡有兩個主要的問題: ①它不方便地傳遞參數給父級類型; ②父級類型當中的參考類型被所有的實例共享
2)ES5 提供了Object.create() 方法來實現繼承
————做兼容 //shim垫片 function create(obj){ if(Object.create){ return Object.create(obj); }else{ function Foo(){} Foo.prototype = obj; return new Foo(); } }
這個方法是ES5的新特性,其實就是複製繼承。
3)拷貝繼承
var obj = {}; obj.extend = function(obj){ for(var k in obj){ this[k] = obj[k]; } }
4)借用建構函式繼承
-被借用的建構函式中原型上的成員沒有被借過來
function Animal(name){ this.name = name; } function Mouse(nickname){ Animal.call(this,'老鼠'); this.nickname = nickname; } var m = new Mouse('杰瑞'); console.log(m.name); console.log(m.nickname);
存在的問題:可以解決原型繼承當中傳參問題,但是父親類型當中的原型物件上的成員(屬性和方法)不能被繼承到
5)組合繼承
——prototype物件是有動態性的
function Person(name){ this.name = name; } Person.prototype.showName = function(){ console.log(this.name); } function Student(name,age){ Person.call(this,name); this.age = age; } Student.prototype = new Person(); Student.prototype.contructor = Student; Student.prototype.showAge = function(){ console.log(this.age); } var stu = new Student('张三',12); stu.showName(); stu.showAge();
【原型繼承借用建構函式繼承】它的特點就是屬性每個實例一份,方法共享
【小結】套用一句很粗暴的話,所謂原型鏈就是找媽的一種行為方式,就可以理解為人是人他媽生的,妖是妖他媽生的。原型鏈的核心其實只有一個:屬性共享和獨立的控制,當你的物件實例需要獨立的屬性,所有做法的本質都是在物件實例裡面創造屬性。若不考慮太多,你大可以在Person裡面直接定義你所需要獨立的屬性來覆寫原型的屬性。總之,使用原型繼承的時候,要對於原型中的屬性要特別注意,因為他們都是牽一發而動全身的存在。現在最常用的方法是組合模式。
1、原型鏈
1)建構子、原型與實例的關係式
①建構子都有一個屬性prototype,這個屬性是一個物件(ObjectObject的實例)
②原型物件prototype裡面有一個constructor屬性,該屬性指向原型物件所屬的建構子
③物件所屬的建構函式
③物件具有一個_proto_實例屬性,該屬性也指向建構子的實例物件原型對象,它是一個非標準屬性,不可以用於編程,它是用於瀏覽器自己使用的
2)prototype與_proto_的關係
①prototype是構造函數的屬性
### ②_proto_是實例物件的屬性###-這兩者都指向同一個物件
【總結】i)函數也是物件,物件不一定是函數;值對集合;鍵值對當中的值可以是任意資料類型的值
iii)物件就是一個容器,而這個容器當中放的是(屬性與方法)
搜尋
①在存取物件的某個成員的時候會先在物件中找出是否存在
②如果目前物件中沒有找到建構函式的原型物件中找出建構子的原型物件中沒有就可以尋找建構函數的原型物件中。 ## ③如果原型物件中沒有找到就到原型物件的原型上找
④知道Object的原型物件的原型是null為止
2、Function
###########################111]12212212、Function##########################11 —所有函數都是Function的實例###### ①本地物件:獨立於宿主環境(瀏覽器)的物件-包括Object、Array、Date、RegExp、Function、Error、Number、String、Boolean## #### ②內建物件-包括Math、Global(window,在js中是全域變數),使用的時候不需要new###### ③宿主物件-包括自訂物件、DOM、BOM# #####【推薦學習:###javascript高階教學###】####以上是如何理解javascript原型鏈的詳細內容。更多資訊請關注PHP中文網其他相關文章!