面向?qū)ο蟮木幊蹋?)

之前講過什么是面向?qū)ο缶幊?/a>府适,然后寫了兩個簡單的小實例唯绍,今天繼續(xù)研究。

一 包裝對象

1.什么是包裝對象

先來看這段代碼:

var str = 'hello';
alert( typeof str ); //string

str.charAt(0);
str.indexOf('e');

很明顯,str的類型是string窘游,按理說只有對象才會有屬性和方法窜觉,為什么字符串可以使用方法呢总珠?

其實這就是包裝對象。

分別與數(shù)值、字符串椰于、布爾值相對應的NumberString骨望、Boolean這三個原生對象可以把原始類型的值變成(包裝成)對象粪牲。

這三個對象作為構(gòu)造函數(shù)使用(帶有new)時,可以將原始類型的值轉(zhuǎn)為對象赢织;作為普通函數(shù)使用時(不帶有new)亮靴,可以將任意類型的值,轉(zhuǎn)為原始類型的值于置。

2.原始類型的自動轉(zhuǎn)換

在上面的代碼中茧吊,執(zhí)行到str.charAt(0);的時候, 基本類型會找到對應的包裝對象類型八毯,然后包裝對象把所有的屬性和方法給了基本類型搓侄,然后包裝對象消失。這就叫原始類型的自動轉(zhuǎn)換话速。

但是這個對象是臨時的讶踪,我們不能對它進行修改。

var str = 'hello';
alert(str.length);  //5

str.number = 10;
alert( str.number );  //undefined

上面代碼中泊交,str是一個字符串俊柔,本身不是對象,不能調(diào)用length屬性活合。JavaScript引擎自動將其轉(zhuǎn)為包裝對象雏婶,在這個對象上調(diào)用length屬性。這個臨時對象是只讀的白指,無法修改留晚。所以,字符串無法添加新屬性告嘲。

3.包裝對象自定義方法

包裝對象還可以在原型上添加自定義方法和屬性错维,供原始類型的值直接調(diào)用。

var str = 'hello';

String.prototype.lastValue = function(){
    return this.charAt(this.length-1);
};

alert( str.lastValue() );  //o

二 原型鏈

1 什么是原型鏈

在下面的例子中橄唬,我們創(chuàng)建了兩個構(gòu)造函數(shù)赋焕,其中LandRover的原型對象又是以Car的原型對象為原型創(chuàng)建的。圖示中的紅色線即為原型鏈仰楚。

function Car(Logo) {
    this.logo = logo || "unknown name";
}
//設(shè)置Car的prototype屬性
Car.prototype = {
    start:function() {
         console.log('%s start',this.logo);
    },
    run:function() {
         console.log('%s run',this.logo);
    },
    stop:function() {
         console.log('%s stop',this.logo);
    }
};

//又創(chuàng)建一個構(gòu)造函數(shù)landRover
function LandRover(serialno) {
    this.serialNumber = serialno;  //序列號
}
//設(shè)置LandRover的prototype屬性
LandRover.prototype = new Car("landRover"); //使用Car創(chuàng)建一個新對象隆判,并把它賦給LandRover構(gòu)造函數(shù)的原型

//創(chuàng)建LandRover對象
var landRover1 = new LandRover("1000");
var landRover2 = new LandRover("1001");
Paste_Image.png

Car.prototype對象也是由Object來創(chuàng)建的犬庇,所以它的原型指向Object.prototype

2 修改、刪除屬性時侨嘀,只能修改臭挽、刪除對象自身的屬性

①訪問:假如我們想訪問landRover1的serialNumber屬性,那么直接在它的本身就可以找到咬腕;如果我們要訪問landRover1的toString方法欢峰,它本身是沒有的,就會順著原型鏈一直網(wǎng)上尋找涨共,知道找到或者沒有纽帖。

②修改及刪除:

操作1:

landRover1.Logo = landRover1;

因為landRover1本身并沒有Logo,雖然它可以訪問landRover.protoype的Logo屬性举反,但是它無法修改抛计,所以這時它會在自己身上加一個Logo屬性,并賦值為landRover1照筑,對landRover.protoype中的Logo屬性并無影響

操作2:

delete(landRover1.Logo);

我們把landRover1的Logo屬性刪除了吹截,但是當我們訪問landRover1.Logo時,還是可以訪問到的凝危,因為它刪除的是自身的屬性波俄,對原型上的屬性無影響,即使再次做修改操作蛾默,也是無效的

3 在javascript中懦铺,一切都是對象

①函數(shù)在JS中也是對象,所以支鸡,Car和LandRover 這些構(gòu)造函數(shù)其實也是一個對象冬念,既然是對象,肯定就有原型牧挣,而Car和LandRover 則是由new Function創(chuàng)建出來的急前,所以LandRover和Car都有一個原型即Function.prototype。

②而Function.prototype是由new Object創(chuàng)建出來的瀑构,所以Function.prototype的原型指向Object的原型裆针,也就是Object.prototype。

③Object.prototype是所有原型的頂層寺晌。


Paste_Image.png

三 面向?qū)ο蟮囊恍傩院头椒?/h3>

1.hasOwnProperty()

1)作用:判斷傳入的屬性是否為對象自身的屬性

理解原型查找原理:對象查找先在該構(gòu)造函數(shù)內(nèi)查找對應的屬性世吨,如果該對象沒有該屬性的話,那么javascript會試著從該原型上去查找呻征,如果原型對象中也沒有該屬性的話耘婚,那么它們會從原型中的原型去查找,直到查找的Object.prototype也沒有該屬性的話陆赋,那么就會返回undefined沐祷。

2)實例

因此我們僅想在該對象內(nèi)查找的話嚷闭,為了提高性能,我們可以使用hasOwnProperty()來判斷該對象內(nèi)有沒有該屬性戈轿,如果有的話,就執(zhí)行代碼(使用for-in循環(huán)查找)阵子,如下:

var obj = {
    "name":'moon',
    "age":'28'
};
// 使用for-in循環(huán)
for(var i in obj) {
    if(obj.hasOwnProperty(i)) {
        console.log(obj[i]);    //moon 28
    }
}

如上使用for-in循環(huán)查找對象里面的屬性思杯,但是我們需要明白的是:for-in循環(huán)查找對象的屬性,它是不保證順序的挠进,for-in循環(huán)和for循環(huán)最本質(zhì)的區(qū)別是:for循環(huán)是有順序的色乾,for-in循環(huán)遍歷對象是無序的,因此我們?nèi)绻枰獙ο蟊WC順序的話领突,可以把對象轉(zhuǎn)換為數(shù)組來暖璧,然后再使用for循環(huán)遍歷即可;

2.constructor

1)作用:查看對象的構(gòu)造函數(shù)
function Aaa(){
}
var a1 = new Aaa();
alert( a1.constructor );  //Aaa
2)每個原型都會自動添加constructor屬性

prototype對象有一個constructor屬性,默認指向prototype對象所在的構(gòu)造函數(shù)君旦。

function Aaa(){
}
//系統(tǒng)會自動添加上
//Aaa.prototype.constructor = Aaa;   
//每一個函數(shù)都會有的澎办,都是自動生成的

由于constructor屬性定義在prototype對象上面,意味著可以被所有實例對象繼承金砍。

3)避免修改construtor屬性
function A() {}
var a = new A();
a instanceof A // true

function B() {}
A.prototype = B.prototype;
a instanceof A // false

上面代碼中局蚀,a是A的實例。修改了A.prototype以后恕稠,constructor屬性的指向就變了琅绅,導致instanceof運算符失真。

所以鹅巍,修改原型對象時千扶,一般要同時校正constructor屬性的指向。

// 避免這種寫法
C.prototype = {
  method1: function (...) { ... },
  // ...
};

// 較好的寫法
C.prototype = {
  constructor: C,
  method1: function (...) { ... },
  // ...
};

// 好的寫法
C.prototype.method1 = function (...) { ... };

3.instanceof運算符

1)作用:對象與構(gòu)造函數(shù)在原型鏈上是否有關(guān)系
function Aaa(){
}

var a1 = new Aaa();
alert( a1 instanceof Object );  //true
2)可以用來判斷數(shù)據(jù)類型

4.toString() :

1)作用:把對象轉(zhuǎn)成字符串

這個方法是原型上的骆捧,我們可以修改這個方法澎羞,但是不建議這樣做

var arr = [1,2,3];

Array.prototype.toString = function(){
    return this.join('+');
};

alert( arr.toString() );  //'1+2+3'
2)利用toString方法來做類型判斷

四 對象的繼承

1.什么是繼承

  • 在原有對象的基礎(chǔ)上,略作修改敛苇,得到一個新的對象
  • 不影響原有對象的功能

當新創(chuàng)建的對象添加了新的屬性和方法時煤痕,肯定不能直接用new+構(gòu)造函數(shù)這種方法來直接創(chuàng)建了,因為在添加屬性或者方法的時候接谨,也會影響到原來的對象摆碉。那我們應該如何實現(xiàn)呢?

2.拷貝繼承

方式:

  • 屬性的繼承 : 調(diào)用父類的構(gòu)造函數(shù) call
  • 方法的繼承 : for in : 拷貝繼承 (jquery也是采用拷貝繼承extend)
function Person(name) {
    this.name = name;
}
Person.prototype.talk = function(name) {
    console.log('My name is '+this.name);
};
var p1 = new Person('moon');
// console.log(p1.name);
// p1.talk();
function Person1(name,age) {
    Person.call(this,name); //這里需要改變this的指向
    this.age = age;
}
function extend(obj1,obj2){
    for (var attr in obj2) {
        obj1[attr] = obj2[attr]; //這個地方不能用"."
    }
}
extend(Person1.prototype,Person.prototype);
var p2 = new Person1('yao',18);
console.log(p1.name); //moon
console.log(p2.name); //yao
p2.talk(); //My name is yao

3.類繼承

利用構(gòu)造函數(shù)(類)繼承的方式脓豪。

首先聲明巷帝,JS中是沒有類的概念的,這里說的類是把JS中的構(gòu)造函數(shù)看做類扫夜。

先來看看所謂的一步繼承法

function Person1() {
    this.name = [1,2,3];
}
Person1.prototype.talk = function(name) {
    alert(this.name);
};

function Person2() {}
Person2.prototype = new Person1();

var p1 = new Person2();
p1.talk();
alert( p1.constructor ); //Person1

p1.name.push(4);
var p2 = new Person2();
console.log(p1.name);  //[1,2,3,4]
console.log(p2.name);  //[1,2,3,4]

缺陷:

1.修改了構(gòu)造函數(shù)的指向

2.創(chuàng)建出來的對象之間會相互影響

正確做法:
屬性和方法分開繼承楞泼。

function Person1() {
    this.name = [1,2,3];
}
Person1.prototype.talk = function(name) {
    alert(this.name);
};

function Person2() {
    Person1.call(this); //屬性繼承仍采取之前的call調(diào)用父類的構(gòu)造函數(shù)的方法
}
function Foo() {}  //避免繼承屬性驰徊,只繼承方法
Foo.prototype = Person1.prototype;
Person2.prototype = new Foo();
Person2.prototype.constructor = Person2; //修正指向問題

var p1 = new Person2();

p1.talk();
alert( p1.constructor );
p1.name.push(4);
var p2 = new Person2();
console.log(p1.name);  //[1,2,3,4]
console.log(p2.name);  //[1,2,3]

4.原型繼承

利用原型prototype來實現(xiàn)繼承,一般用來下面這種情況:

function cloneObj(obj){

    var F = function(){};
    F.prototype = obj;
    return new F();

}
var a = {
    name : '小明'
};

var b = cloneObj(a);
alert( b.name ); // 小明

b.name = '小強';
alert( b.name ); //小強
alert( a.name ); //小明

我們來看一下關(guān)系圖堕阔,假設(shè) new F() =f1

無標題.png
 第一次執(zhí)行alert( b.name );時棍厂,因為b沒有這個屬性,所以它會順著原型鏈往上找超陆,知道找到a下面的name:小明

 執(zhí)行b.name = '小強';因為b本身是沒有name這個屬性的牺弹,它雖然可以訪問a下面的name屬性,但是無法修改时呀,所以這時它會在自己身上加一個name屬性张漂,并賦值為“小強”,對a中的name屬性并無影響

 執(zhí)行alert( a.name ); 的時候谨娜,根據(jù)原型鏈的查找規(guī)則航攒,它肯定不會查找到b下面去,更何況a本身就有name屬性趴梢,所以彈出來的還是“小明”

5.小結(jié):

  • 拷貝繼承: 通用型的,有new或無new的時候都可以

  • 類式繼承: 通過new構(gòu)造函數(shù)形式

  • 原型繼承: 無new的對象

如有錯誤漠畜,煩請告知,非常感謝坞靶。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末盆驹,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子滩愁,更是在濱河造成了極大的恐慌躯喇,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件硝枉,死亡現(xiàn)場離奇詭異廉丽,居然都是意外死亡,警方通過查閱死者的電腦和手機妻味,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進店門正压,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人责球,你說我怎么就攤上這事焦履。” “怎么了雏逾?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵嘉裤,是天一觀的道長。 經(jīng)常有香客問我栖博,道長屑宠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任仇让,我火速辦了婚禮典奉,結(jié)果婚禮上躺翻,老公的妹妹穿的比我還像新娘。我一直安慰自己卫玖,他們只是感情好公你,可當我...
    茶點故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著假瞬,像睡著了一般陕靠。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上笨触,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天懦傍,我揣著相機與錄音雹舀,去河邊找鬼芦劣。 笑死,一個胖子當著我的面吹牛说榆,可吹牛的內(nèi)容都是我干的虚吟。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼签财,長吁一口氣:“原來是場噩夢啊……” “哼串慰!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起唱蒸,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤邦鲫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后神汹,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體庆捺,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年屁魏,在試婚紗的時候發(fā)現(xiàn)自己被綠了滔以。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡氓拼,死狀恐怖你画,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情桃漾,我是刑警寧澤坏匪,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站撬统,受9級特大地震影響剥槐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜宪摧,卻給世界環(huán)境...
    茶點故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一粒竖、第九天 我趴在偏房一處隱蔽的房頂上張望颅崩。 院中可真熱鬧,春花似錦蕊苗、人聲如沸沿后。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽尖滚。三九已至,卻和暖如春瞧柔,著一層夾襖步出監(jiān)牢的瞬間漆弄,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工造锅, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留撼唾,地道東北人。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓哥蔚,卻偏偏與公主長得像倒谷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子糙箍,可洞房花燭夜當晚...
    茶點故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容