首頁  >  文章  >  web前端  >  JavaScript中prototype的使用詳解

JavaScript中prototype的使用詳解

黄舟
黄舟原創
2017-11-23 10:19:311997瀏覽

相信很多用過JavaScript的小夥伴們肯定都對prototype都有一些了解,但是prototype這究竟是個什麼東西卻讓初學者不知所措,只知道函數都會有一個prototype屬性,可以為其添加函數供實例訪問,其它的就不清楚了,今天就給大家介紹下JavaScript中prototype的使用詳解!

用過JavaScript的同學們肯定都對prototype如雷貫耳,但是這究竟是個什麼東西卻讓初學者莫衷一是,只知道函數都會有一個prototype屬性,可以為其添加函數供實例訪問,其它的就不清楚了,最近看了一些JavaScript高階程式設計,終於揭開了其神秘面紗。

每個函數都有一個prototype屬性,這個屬性是指向一個對象的引用,這個對象稱為原型對象,原型對象包含函數實例共享的方法和屬性,也就是說將函數用作建構函式呼叫(使用new運算元呼叫)的時候,新建立的物件會從原型物件繼承屬性和方法

私有變數、函數

在具體說prototype前說幾個相關的東東,可以更好的理解prototype的設計意圖。之前寫的一篇JavaScript 命名空間文章中提到過JavaScript的函數作用域,在函數內定義的變數和函數如果不對外提供接口,那麼外部將無法訪問到,也就是變成私有變數和私有函數。

 程式碼如下:

function Obj(){
                var a=0; //私有变量
                var fn=function(){ //私有函数
                }
            }

這樣在函數物件Obj外部無法存取變數a和函數fn,它們就變成私有的,只能在Obj內部使用,即使是函數Obj的實例仍然無法存取這些變數和函數

程式碼如下:

var o=new Obj();
            console.log(o.a); //undefined
            console.log(o.fn); //undefined

# 靜態變數、函數

定義一個函數後面透過「.」為其添加的屬性和函數,透過物件本身仍然可以存取得到,但是其實例卻訪問不到,這樣的變數和函數分別被稱為靜態變數和靜態函數,用過Java、 C#的同學很好理解靜態的意思。

程式碼如下:

function Obj(){
            }
            Obj.a=0; //静态变量
            Obj.fn=function(){ //静态函数
            }
            console.log(Obj.a); //0
            console.log(typeof Obj.fn); //function
            var o=new Obj();
            console.log(o.a); //undefined
            console.log(typeof o.fn); //undefined

實例變數、函數

物件導向程式設計中除了一些函式庫函數我們還是希望在物件定義的時候同時定義一些屬性和方法,實例化後可以訪問,JavaScript也能做到這樣

程式碼如下:

function Obj(){
                this.a=[]; //实例变量
                this.fn=function(){ //实例方法
                }
            }
            console.log(typeof Obj.a); //undefined
            console.log(typeof Obj.fn); //undefined
            var o=new Obj();
            console.log(typeof o.a); //object
            console.log(typeof o.fn); //function

這樣可以達到上述目的,然而

程式碼如下:

function Obj(){
                this.a=[]; //实例变量
                this.fn=function(){ //实例方法
                }
            }
            var o1=new Obj();
            o1.a.push(1);
            o1.fn={};
            console.log(o1.a); //[1]
            console.log(typeof o1.fn); //object
            var o2=new Obj();
            console.log(o2.a); //[]
            console.log(typeof o2.fn); //function

上面的程式碼運行結果完全符合預期,但同時也說明一個問題,在o1中修改了a和fn,而在o2中沒有改變,由於數組和函數都是對象,是引用型,這就說明o1中的屬性和方法與o2中的屬性與方法雖然同名但卻不是一個引用,而是對Obj對象定義的屬性和方法的複製。

這個對屬性來說沒有什麼問題,但是對於方法來說問題就很大了,因為方法都是在做完全一樣的功能,但是卻又兩份複製,如果一個函數物件有上千和實例方法,那麼它的每個實例都要保持一份上千個方法的複製,這顯然是不科學的,這可腫麼辦呢,prototype應運而生。

prototype

無論什麼時候,只要建立了一個新函數,就會根據一組特定的規則為該函數建立一個prototype屬性,預設情況下prototype屬性會預設得到一個constructor(建構子)屬性,這個屬性是一個指向prototype屬性所在函數的指針,有些繞了啊,寫程式碼、上圖!

程式碼如下:

function Person(){
            }

JavaScript中prototype的使用詳解

根據上圖可以看出Person物件會自動獲得prototyp屬性,而prototype也是一個對象,會自動取得一個constructor屬性,該屬性正是指向Person物件。

當呼叫建構函式建立一個實例的時候,實例內部會包含一個內部指標(很多瀏覽器這個指標名字為proto)指向建構函式的prototype,這個連線存在於實例和建構函式的prototype之間,而不是實例與建構子之間。

程式碼如下:

function Person(name){
                this.name=name;
            }
            Person.prototype.printName=function(){
                alert(this.name);
            }
            var person1=new Person('Byron');
            var person2=new Person('Frank');

JavaScript中prototype的使用詳解

Person的實例person1中包含了name屬性,同時自動產生一個proto屬性,該屬性指向Person的prototype,可以訪問到prototype內定義的printName方法,大概就是這個樣子的

JavaScript中prototype的使用詳解

写段程序测试一下看看prototype内属性、方法是能够共享

代码如下:

function Person(name){
                this.name=name;
            }
            Person.prototype.share=[];
            Person.prototype.printName=function(){
                alert(this.name);
            }
            var person1=new Person('Byron');
            var person2=new Person('Frank');
            person1.share.push(1);
            person2.share.push(2);
            console.log(person2.share); //[1,2]

果不其然!实际上当代码读取某个对象的某个属性的时候,都会执行一遍搜索,目标是具有给定名字的属性,搜索首先从对象实例开始,如果在实例中找到该属性则返回,如果没有则查找prototype,如果还是没有找到则继续递归prototype的prototype对象,直到找到为止,如果递归到object仍然没有则返回错误。同样道理如果在实例中定义如prototype同名的属性或函数,则会覆盖prototype的属性或函数。

代码如下:

function Person(name){                
this.name=name;            
}            
Person.prototype.share=[];
var person=new Person('Byron');            
person.share=0;            
console.log(person.share); //0而不是prototype中的[]

构造简单对象

当然prototype不是专门为解决上面问题而定义的,但是却解决了上面问题。了解了这些知识就可以构建一个科学些的、复用率高的对象,如果希望实例对象的属性或函数则定义到prototype中,如果希望每个实例单独拥有的属性或方法则定义到this中,可以通过构造函数传递实例化参数。

代码如下:

function Person(name){
                this.name=name;
            }
            Person.prototype.share=[];
            Person.prototype.printName=function(){
                alert(this.name);
            }

总结:

相信通过对本文的详细学习,很多小伙伴都知道JavaScript中prototype的使用有了进一步的了解,希望对你的工作有所帮助!

相关推荐:

JavaScript向对象添加属性和方法的属性prototype

Js如何使用prototype实现自定义数组的案例

JavaScript原型链prototype属性和方法实例详解

详细介绍javascript使用prototype实现OOP继承的方法

以上是JavaScript中prototype的使用詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn