亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

深入學習JavaScript中的原型prototype

2019-11-20 11:50:18
字體:
來源:轉載
供稿:網友

javascript 是一種 prototype based programming 的語言, 而與我們通常的 class based programming 有很大 的區別,我列舉重要的幾點如下:

1.函數是first class object, 也就是說函數與對象具有相同的語言地位
2.沒有類,只有對象
3.函數也是一種對象,所謂的函數對象
4.對象是按 引用 來傳遞的
那么這種 prototype based programming 的語言如何實現繼承呢(OO的一大基本要素), 這也便是 prototype 的由來.

看下面的代碼片斷:

function foo(a, b, c){return a*b*c;}alert(foo.length);alert(typeof foo.constructor);alert(typeof foo.call);alert(typeof foo.apply);alert(typeof foo.prototype);

對于上面的代碼,用瀏覽器運行后你會發現:

1.length: 提供的是函數的參數個數
2.prototype: 是一個object
3.其它三個都是function
而對于任何一個函數的聲明,它都將會具有上面所述的5個property(方法或者屬性).

下面我們主要看下prototype.

// prototypefunction Person(name, gender){this.name = name;this.gender = gender;this.whoAreYou = function(){//這個也是所謂的closure, 內部函數可以訪問外部函數的變量var res = "I'm " + this.name + " and I'm a " + this.gender +".";return res;};}// 那么在由Person創建的對象便具有了下面的幾個屬性Person.prototype.age = 24;Person.prototype.getAge = function(){return this.age;};flag = true;if (flag){var fun = new Person("Tower", "male");alert(fun.name);alert(fun.gender);alert(fun.whoAreYou());alert(fun.getAge());}Person.prototype.salary = 10000;Person.prototype.getSalary = function(){return this.name + " can earn about " + this.salary + "RMB each month." ;};// 下面就是最神奇的地方, 我們改變了Person的prototype,而這個改變是在創建fun之后// 而這個改變使得fun也具有了相同的屬性和方法// 繼承的意味即此if (flag){alert(fun.getSalary());alert(fun.constructor.prototype.age);//而這個相當于你直接調用 Person.prototype.agealert(Person.prototype.age);}

從上面的示例中我們可以發現,對于prototype的方法或者屬性,我們可以 動態地 增加, 而由其創建的 對象自動會 繼承 相關的方法和屬性.

另外,每個對象都有一個 constructor 屬性,用于指向創建其的函數對象,如上例中的 fun.constructor 指向的 就是 Person.

那么一個疑問就自然產生了, 函數對象中自身聲明的方法和屬性與prototype聲明的對象有什么差別?

有下面幾個差別:

1.自身聲明的方法和屬性是 靜態的, 也就是說你在聲明后,試圖再去增加新的方法或者修改已有的方法,并不會 對由其創建的對象產生影響, 也即 繼承 失敗
2.而prototype可以動態地增加新的方法或者修改已有的方法, 從而是 動態的 ,一旦 父函數對象 聲明了相關 的prototype屬性,由其創建的對象會 自動繼承 這些prototype的屬性.
繼續上面的例子:

flag = true;// 函數內部聲明的方法是靜態的,無法傳遞的Person.school = "ISCAS";Person.whoAreYou = function(){return "zhutao";};//動態更改聲明期的方法,并不會影響由其創建的對象的方法, 即所謂的 靜態if (flag){alert(Person.school);alert(fun.school);//輸出的是 "undefined"alert(Person.whoAreYou()); //輸出 zhutaoalert(fun.whoAreYou()); // I'm Tower and I'm a male.}Person.prototype.getSalary = function(){return "I can earn 1000000 USD";};if (flag){alert(fun.getSalary());//已經繼承了改變, 即所謂的 動態}

既然有函數對象本身的屬性, 也有prototype的屬性, 那么是由其創建的對象是如何搜索相應的屬性的呢?

基本是按照下面的流程和順序來進行.

1.先去搜索函數對象本身的屬性,如果找到立即執行
2.如果1沒有找到,則會去搜索prototype屬性,有2種結果,找到則直接執行,否則繼續搜索 父對象 的 父對象 的prototype, 直至找到,或者到達 prototype chain 的結尾(結尾會是Object對象)
上面也回答如果函數對象本身的屬性與prototype屬性相同(重名)時的解決方式, 函數本身的對象 優先 .

prototype 的典型示例

用過 jQuery 或者 Prototype 庫的朋友可能知道,這些庫中通常都會有 trim 這個方法。

示例:

String.prototype.trim = function() { return this.replace(/^/s+|/s+$/g, '');};

trim 用法:

' foo bar '.trim(); // 'foo bar'

但是這樣做又有一個缺點,因為比較新版本的瀏覽器中的 JavaScript 引擎在 String 對象中本身就提供了 trim 方法, 那么我們自己定義的 trim 就會覆寫它自帶的 trim。其實,我們在定義 trim 方法之前,可以做個簡單的檢測,看是否需要自己添加這個方法:

if(!String.prototype.trim) { String.prototype.trim = function() { return this.replace(/^/s+|/s+$/g, ''); };}

原型鏈

JavaScript 中定義或實例化任何一個對象的時候,它都會被附加一個名為 __proto__ 的隱藏屬性,原型鏈正是依靠這個屬性才得以形成。但是千萬別直接訪問 __proto__ 屬性,因為有些瀏覽器并不支持直接訪問它。另外 __proto__ 和 對象的 prototype 屬性也不是一回事,它們各自有各自的用途。

怎么理解呢?其實,當我們創建 myObject 函數時,實際上是創建了一個 Function 類型的對象:

console.log(typeof myObject); // function

這里要說明一下,Function 是 JavaScript 中預定義的一個對象,所以它也有自己預定義的屬性(如 length 和 arguments)和方法(如 call 和 apply),當然也有 __proto__,以此實現原型鏈。也就是說,JavaScript 引擎內可能有類似如下的代碼片段:

Function.prototype = { arguments: null, length: 0, call: function() { // secret code }, apply: function(){ // secret code }, ...};

事實上,JavaScript 引擎代碼不可能這樣簡單,這里只是描述一下原型鏈是如何工作的。

我們定義了一個函數 myObject,它還有一個參數 name,但是并沒有給它任何其它屬性,例如 length 或者其它方法,如 call。那么下面這段代碼為啥能正常執行呢?

console.log(myObject.length); // 結果:1,是參數的個數

這是因為我們定義 myObject 時,同時也給它定義了一個 __proto__ 屬性,并賦值為 Function.prototype(參考前面的代碼片段),所以我們能夠像訪問其它屬性一樣訪問 myObject.length,即使我們并沒有定義這個屬性,因為它會順著 __proto__ 原型鏈往上去找 length,最終在 Function 里面找到了。

那為什么找到的 length 屬性的值是 1,而不是 0 呢,是什么時候給它賦值的呢?由于 myObject 是 Function 的一個實例:

console.log(myObject instanceof Function); // trueconsole.log(myObject === Function); // false

當實例化一個對象的時候,對象的 __proto__ 屬性會被賦值為其構造者的原型對象,在本示例中就是 Function,此時構造器回去計算參數的個數,改變 length 的值。

console.log(myObject.__proto__ === Function.prototype); // true

而當我們用 new 關鍵字創建一個新的實例時,新對象的 __proto__ 將會被賦值為 myObject.prototype,因為現在的構造函數為 myObject,而非 Function。

var myInstance = new myObject('foo');console.log(myInstance.__proto__ === myObject.prototype); // true

新對象除了能訪問 Function.prototype 中繼承下來的 call 和 apply 外,還能訪問從 myObject 中繼承下來的 getName 方法:

console.log(myInstance.getName()); // foo var mySecondInstance = new myObject('bar'); console.log(mySecondInstance.getName()); // barconsole.log(myInstance.getName()); // foo

其實這相當于把原型對象當做一個藍本,然后可以根據這個藍本創建 N 個新的對象。

再看一個多重prototype鏈的例子:

// 多重prototype鏈的例子function Employee(name){this.name = "";this.dept = "general";this.gender = "unknown";}function WorkerBee(){this.projects = [];this.hasCar = false;}WorkerBee.prototype = new Employee; // 第一層prototype鏈function Engineer(){this.dept = "engineer"; //覆蓋了 "父對象"this.language = "javascript";}Engineer.prototype = new WorkerBee; // 第二層prototype鏈var jay = new Engineer("Jay");if (flag){alert(jay.dept); //engineer, 找到的是自己的屬性alert(jay.hasCar); // false, 搜索到的是自己上一層的屬性alert(jay.gender); // unknown, 搜索到的是自己上二層的屬性}

上面這個示例的對象關系如下:

201581395745486.jpg (222×362)

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
亚洲视频日韩精品| 91精品国产91久久久久久不卡| 欧美激情一区二区三区在线视频观看| 韩国精品美女www爽爽爽视频| 欧美激情videos| 欧美性猛交xxxx乱大交极品| 国产中文日韩欧美| 国产精品7m视频| 欧美激情久久久久久| 欧美亚洲视频在线看网址| 欧美性生交大片免网| 日韩在线观看免费高清| 久久免费精品日本久久中文字幕| 日本19禁啪啪免费观看www| 久久精品久久久久| 亚洲欧美精品伊人久久| 国产一区二区精品丝袜| 欧美日韩国产成人在线| 91精品国产91久久久久久不卡| 最近2019中文字幕第三页视频| 91久久精品国产91久久| 亚洲综合色av| 懂色av一区二区三区| 色婷婷久久一区二区| 亚洲一区中文字幕| 日韩在线不卡视频| 日韩av在线免费看| 久久99国产精品久久久久久久久| 国产在线视频欧美| 成人免费在线视频网址| 日韩精品在线播放| 91高清免费在线观看| 亚洲区在线播放| 亚洲国产精品久久91精品| 国产福利精品视频| 日韩少妇与小伙激情| 国产精品黄色影片导航在线观看| 麻豆成人在线看| 国产精品黄页免费高清在线观看| 久久精品国产成人| 亚洲国产精品一区二区久| 国产69精品久久久| www.日韩视频| 成人欧美一区二区三区黑人孕妇| 色偷偷偷综合中文字幕;dd| 九九精品在线观看| 欧美亚洲激情在线| 欧美福利视频在线| 日韩av在线网| 亚洲free嫩bbb| 一道本无吗dⅴd在线播放一区| 久久精视频免费在线久久完整在线看| 日韩在线视频免费观看高清中文| 亚洲欧美在线一区二区| 成人性教育视频在线观看| 久久久免费观看视频| 成人美女免费网站视频| 日韩中文有码在线视频| 国内精品久久久久久久| 一区二区三区无码高清视频| 亚洲人成毛片在线播放| 国产在线精品自拍| 色综合久久精品亚洲国产| 三级精品视频久久久久| 成人精品久久一区二区三区| 国产精品久久9| 韩曰欧美视频免费观看| 日韩av在线高清| 欧美二区乱c黑人| 精品国产美女在线| 亚洲性视频网址| 亚洲色无码播放| 日韩女优人人人人射在线视频| 色综合久久天天综线观看| 91久久久久久久一区二区| 欧美一区二区三区免费视| 欧美一级淫片videoshd| 美女国内精品自产拍在线播放| 国产一区二区三区高清在线观看| 亚洲一区二区三区视频| 中文字幕精品影院| 成人精品aaaa网站| 欧美中文在线字幕| 自拍偷拍亚洲在线| 欧洲美女7788成人免费视频| 国内精品久久久久久久久| 自拍偷拍免费精品| 性欧美在线看片a免费观看| 奇门遁甲1982国语版免费观看高清| 欧美极品在线视频| 韩国精品久久久999| 久久国产视频网站| 一本大道香蕉久在线播放29| 日韩在线视频播放| 欧美三级免费观看| 日韩精品视频观看| 九九精品视频在线| 日韩欧美在线视频日韩欧美在线视频| 亚洲国产精品人人爽夜夜爽| 久久久久中文字幕2018| 欧美在线性视频| 成人国产亚洲精品a区天堂华泰| 亚洲激情在线观看视频免费| 亚洲欧美激情另类校园| 国产一区二区在线免费视频| 国产亚洲欧美日韩一区二区| 国产视频自拍一区| 国产精品久久久久久久天堂| 日韩精品在线免费| 夜夜嗨av色综合久久久综合网| 欧美精品一本久久男人的天堂| 久久久久久久久久久久av| 日韩欧美国产免费播放| 中文在线资源观看视频网站免费不卡| 亚洲一区精品电影| 中文字幕综合一区| 米奇精品一区二区三区在线观看| 国产91|九色| 羞羞色国产精品| 欧美精品情趣视频| 成人精品福利视频| 成人黄色片网站| 亚洲成人网久久久| 亚洲最大的成人网| 日韩欧美aⅴ综合网站发布| 欧美激情综合色综合啪啪五月| 久久九九全国免费精品观看| 国产精品美女www爽爽爽视频| 成人精品福利视频| 欧美日韩亚洲一区二区| 亚洲精品欧美日韩| 亚洲精品久久久久国产| 欧美性极品少妇精品网站| 成人久久18免费网站图片| 欧美电影在线观看| 日韩有码在线观看| 欧美成人黄色小视频| 国产一区二区在线免费视频| 中文字幕在线精品| 亚洲精品久久久久久久久| 黑人巨大精品欧美一区免费视频| 欧美国产日韩中文字幕在线| 日本欧美一二三区| 国产精品久久久久久久久久新婚| 久久精品国产久精国产一老狼| 国产欧美日韩最新| 亚洲成av人影院在线观看| 欧美激情视频在线| 亚洲高清av在线| 亚洲视频在线免费观看| 97热精品视频官网| xxxxx成人.com| 国产亚洲精品久久久久久| 日韩成人高清在线| 91国语精品自产拍在线观看性色| 亚洲成人精品视频在线观看| 国产精品视频自在线| 国产成人涩涩涩视频在线观看| 久久精品国产精品亚洲| 日韩精品视频在线观看免费| 国产美女91呻吟求| 精品中文字幕久久久久久| 中文字幕精品网| 久久精品一本久久99精品|