亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入學(xué)習(xí)JavaScript中的原型prototype

 更新時(shí)間:2015年08月13日 10:00:02   作者:Tower Joo  
這篇文章主要介紹了深入學(xué)習(xí)JavaScript中的原型prototype,是JavaScript入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下

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

1.函數(shù)是first class object, 也就是說函數(shù)與對(duì)象具有相同的語言地位
2.沒有類,只有對(duì)象
3.函數(shù)也是一種對(duì)象,所謂的函數(shù)對(duì)象
4.對(duì)象是按 引用 來傳遞的
那么這種 prototype based programming 的語言如何實(shí)現(xiàn)繼承呢(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);

對(duì)于上面的代碼,用瀏覽器運(yùn)行后你會(huì)發(fā)現(xiàn):

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

下面我們主要看下prototype.

// prototype
function Person(name, gender)
{
this.name = name;
this.gender = gender;
this.whoAreYou = function(){//這個(gè)也是所謂的closure, 內(nèi)部函數(shù)可以訪問外部函數(shù)的變量
var res = "I'm " + this.name + " and I'm a " + this.gender +".";
return res;
};
}
// 那么在由Person創(chuàng)建的對(duì)象便具有了下面的幾個(gè)屬性
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,而這個(gè)改變是在創(chuàng)建fun之后
// 而這個(gè)改變使得fun也具有了相同的屬性和方法
// 繼承的意味即此
if (flag)
{
alert(fun.getSalary());
alert(fun.constructor.prototype.age);//而這個(gè)相當(dāng)于你直接調(diào)用 Person.prototype.age
alert(Person.prototype.age);
}

從上面的示例中我們可以發(fā)現(xiàn),對(duì)于prototype的方法或者屬性,我們可以 動(dòng)態(tài)地 增加, 而由其創(chuàng)建的 對(duì)象自動(dòng)會(huì) 繼承 相關(guān)的方法和屬性.

另外,每個(gè)對(duì)象都有一個(gè) constructor 屬性,用于指向創(chuàng)建其的函數(shù)對(duì)象,如上例中的 fun.constructor 指向的 就是 Person.

那么一個(gè)疑問就自然產(chǎn)生了, 函數(shù)對(duì)象中自身聲明的方法和屬性與prototype聲明的對(duì)象有什么差別?

有下面幾個(gè)差別:

1.自身聲明的方法和屬性是 靜態(tài)的, 也就是說你在聲明后,試圖再去增加新的方法或者修改已有的方法,并不會(huì) 對(duì)由其創(chuàng)建的對(duì)象產(chǎn)生影響, 也即 繼承 失敗
2.而prototype可以動(dòng)態(tài)地增加新的方法或者修改已有的方法, 從而是 動(dòng)態(tài)的 ,一旦 父函數(shù)對(duì)象 聲明了相關(guān) 的prototype屬性,由其創(chuàng)建的對(duì)象會(huì) 自動(dòng)繼承 這些prototype的屬性.
繼續(xù)上面的例子:

flag = true;
// 函數(shù)內(nèi)部聲明的方法是靜態(tài)的,無法傳遞的
Person.school = "ISCAS";
Person.whoAreYou = function(){
return "zhutao";
};//動(dòng)態(tài)更改聲明期的方法,并不會(huì)影響由其創(chuàng)建的對(duì)象的方法, 即所謂的 靜態(tài)
if (flag)
{
alert(Person.school);
alert(fun.school);//輸出的是 "undefined"
alert(Person.whoAreYou()); //輸出 zhutao
alert(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());//已經(jīng)繼承了改變, 即所謂的 動(dòng)態(tài)
}

既然有函數(shù)對(duì)象本身的屬性, 也有prototype的屬性, 那么是由其創(chuàng)建的對(duì)象是如何搜索相應(yīng)的屬性的呢?

基本是按照下面的流程和順序來進(jìn)行.

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

prototype 的典型示例

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

示例:

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

trim 用法:

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

但是這樣做又有一個(gè)缺點(diǎn),因?yàn)楸容^新版本的瀏覽器中的 JavaScript 引擎在 String 對(duì)象中本身就提供了 trim 方法, 那么我們自己定義的 trim 就會(huì)覆寫它自帶的 trim。其實(shí),我們?cè)诙x trim 方法之前,可以做個(gè)簡單的檢測(cè),看是否需要自己添加這個(gè)方法:

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

原型鏈

JavaScript 中定義或?qū)嵗魏我粋€(gè)對(duì)象的時(shí)候,它都會(huì)被附加一個(gè)名為 __proto__ 的隱藏屬性,原型鏈正是依靠這個(gè)屬性才得以形成。但是千萬別直接訪問 __proto__ 屬性,因?yàn)橛行g覽器并不支持直接訪問它。另外 __proto__ 和 對(duì)象的 prototype 屬性也不是一回事,它們各自有各自的用途。

怎么理解呢?其實(shí),當(dāng)我們創(chuàng)建 myObject 函數(shù)時(shí),實(shí)際上是創(chuàng)建了一個(gè) Function 類型的對(duì)象:

console.log(typeof myObject); // function

這里要說明一下,F(xiàn)unction 是 JavaScript 中預(yù)定義的一個(gè)對(duì)象,所以它也有自己預(yù)定義的屬性(如 length 和 arguments)和方法(如 call 和 apply),當(dāng)然也有 __proto__,以此實(shí)現(xiàn)原型鏈。也就是說,JavaScript 引擎內(nèi)可能有類似如下的代碼片段:

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

事實(shí)上,JavaScript 引擎代碼不可能這樣簡單,這里只是描述一下原型鏈?zhǔn)侨绾喂ぷ鞯摹?/p>

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

console.log(myObject.length); // 結(jié)果:1,是參數(shù)的個(gè)數(shù)

這是因?yàn)槲覀兌x myObject 時(shí),同時(shí)也給它定義了一個(gè) __proto__ 屬性,并賦值為 Function.prototype(參考前面的代碼片段),所以我們能夠像訪問其它屬性一樣訪問 myObject.length,即使我們并沒有定義這個(gè)屬性,因?yàn)樗鼤?huì)順著 __proto__ 原型鏈往上去找 length,最終在 Function 里面找到了。

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

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

當(dāng)實(shí)例化一個(gè)對(duì)象的時(shí)候,對(duì)象的 __proto__ 屬性會(huì)被賦值為其構(gòu)造者的原型對(duì)象,在本示例中就是 Function,此時(shí)構(gòu)造器回去計(jì)算參數(shù)的個(gè)數(shù),改變 length 的值。

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

而當(dāng)我們用 new 關(guān)鍵字創(chuàng)建一個(gè)新的實(shí)例時(shí),新對(duì)象的 __proto__ 將會(huì)被賦值為 myObject.prototype,因?yàn)楝F(xiàn)在的構(gòu)造函數(shù)為 myObject,而非 Function。

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

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

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

其實(shí)這相當(dāng)于把原型對(duì)象當(dāng)做一個(gè)藍(lán)本,然后可以根據(jù)這個(gè)藍(lán)本創(chuàng)建 N 個(gè)新的對(duì)象。

再看一個(gè)多重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"; //覆蓋了 "父對(duì)象"
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, 搜索到的是自己上二層的屬性
}

上面這個(gè)示例的對(duì)象關(guān)系如下:

201581395745486.jpg (222×362)

相關(guān)文章

最新評(píng)論