JS 的面向?qū)ο筇匦?/h1>
一. 概念
- 類:有相同的特征和行為的事物的抽象
- 對象:類的一個實例
面向?qū)ο笳Z言的要求:
一種面向?qū)ο笳Z言需要向開發(fā)者提供四種基本能力:
封裝 - 把相關(guān)的信息(無論數(shù)據(jù)或方法)存儲在對象中的能力
聚集 - 把一個對象存儲在另一個對象內(nèi)的能力
繼承 - 由另一個類(或多個類)得來類的屬性和方法的能力
多態(tài) - 編寫能以多種方法運行的函數(shù)或方法的能力
————————————————W3C:ECMAScript 面向?qū)ο蠹夹g(shù)
面向?qū)ο笳Z言的要求:
一種面向?qū)ο笳Z言需要向開發(fā)者提供四種基本能力:
封裝 - 把相關(guān)的信息(無論數(shù)據(jù)或方法)存儲在對象中的能力
聚集 - 把一個對象存儲在另一個對象內(nèi)的能力
繼承 - 由另一個類(或多個類)得來類的屬性和方法的能力
多態(tài) - 編寫能以多種方法運行的函數(shù)或方法的能力
————————————————W3C:ECMAScript 面向?qū)ο蠹夹g(shù)
ECMAScript 支持這些要求耕蝉,因此可被是看做面向?qū)ο蟮摹?/p>
但是 JS 中沒有類的概念越除,而且繼承等的方式非常復(fù)雜且無用炎滞,所以我們也說 JS 不是一個嚴(yán)格面向?qū)ο蟮恼Z言稠诲。
二. 對象的判斷
對于判斷一個變量是否是對象,我們通常選擇兩個方式飒炎。
1. typeOf
typeOf 運算符有一個參數(shù)埋哟,即要檢查的變量或者值。返回值就是這個變量或者值的類型郎汪。
console.log(typeof 12); // number 數(shù)字類型
console.log(typeof 'qweqwe'); // sting 字符串類型
console.log(typeof true); // boolean 布爾類型
var fn = function() {};
console.log(typeof fn); // function 函數(shù)類型
var arr = [1, 2, 'lalala'];
console.log(typeof arr); // object 引用類型
//object 引用類型 不叫對象類型
另外還存在 undefined 類型赤赊。
2. instanceof
instanceof 方法有兩個參數(shù):第一個是要比較的變量或者值,第二個是變量類型煞赢,返回的值是 true / false抛计。
console.log(arr instanceof Object); // true
//表示 arr 是否為引用類型的對象
console.log(fn instanceof Object); // true
console.log(Boolean instanceof Object); // true
console.log(true instanceof Object); // false
console.log(arr instanceof Array); // true
console.log('aa' instanceof String); // false
console.log(123 instanceof Number); // false
//直接寫的123或者"aa"這都是基本類型,除非:
var str = new String('aa');
console.log(str instanceof String); // true
var num = new Number(123);
console.log(num instanceof Number); // true
三. 如何創(chuàng)建一個對象
這里有兩個創(chuàng)建對象方式:
1. 直接創(chuàng)建
var 變量名={
屬性1:值1,
屬性2:值2,
... ...
函數(shù)名: function(){
函數(shù)內(nèi)容
}
}
舉例:
var stu = {
name: 'Tom',
age: 42,
sex: 'female',
sayHi: function() {
console.log(this.name)
}
};
此時我們就創(chuàng)建了一個名為 stu 的對象,這個對象包括三個屬性:name, age, sex照筑。
console.log(stu.age); // 42
同時對象可以自己調(diào)用自己內(nèi)部的函數(shù):
stu.sayHi(); // Tom
2. 對象的構(gòu)造函數(shù)
在第一種直接創(chuàng)建方式中吹截,我們可以想象,如果要批量創(chuàng)建對象凝危,會很繁瑣波俄。所以我們可以創(chuàng)建一個函數(shù),進(jìn)行對象的創(chuàng)建蛾默。
結(jié)構(gòu):
function 構(gòu)造函數(shù)名(參數(shù)1,參數(shù)2,...){
this.屬性1 = 參數(shù)1;
this.屬性2 = 參數(shù)2;
... ...
this.函數(shù)名= function(){
函數(shù)內(nèi)容
}
}
舉例:
function Student(name, age) {
this.name = name;
this.age = age;
this.sayHi = function() {
console.log("i'm " + this.name);
};
};
此時我們就有了一個可以創(chuàng)建對象的函數(shù)懦铺,我們只要輸入對應(yīng)的參數(shù)值,就可以得到有函數(shù)內(nèi)包含的屬性的對象支鸡。
那么我們用構(gòu)造函數(shù)來創(chuàng)建對象:
var stu1 = new Student('Tom', 42);
console.log(stu1.name); // Tom
stu1.sayHi(); // i'm Tom
構(gòu)造函數(shù)創(chuàng)建對象有如下的優(yōu)點:
- 創(chuàng)建對象冬念,將復(fù)雜的內(nèi)容簡化為一個函數(shù)
- 改動方便,改函數(shù)牧挣,改所有對象
四. 原型
1. 概念
每一個構(gòu)造函數(shù)創(chuàng)建的屬性都遠(yuǎn)原型屬性急前,當(dāng)我們在某一個對象內(nèi)創(chuàng)建一個原型屬性,這個屬性就被曝存在了一個獨立于每個對象空間的堵路區(qū)域瀑构,且可以被所有對象訪問到裆针。
2. 原型的基本設(shè)置方式
Student.prototype.school = 'TsingHua';
// 此時我們就創(chuàng)建了一個原型屬性school,而且屬性的值都是一樣的,是TsingHua
// 這個屬性可以被所有對象訪問到
console.log(stu1.school); // TsingHua
同時原型屬性也可以是函數(shù)
Student.prototype.saySchool = function() {
console.log('我的老家就在這個' + this.school);
console.log(this);
};
stu1.saySchool();
// 我的老家就在這個TsingHua
// Student {name: "Tom", age: 42}
3. 屬性獲取順序(原型鏈)
那么,如果此時有一個對象的 school 是其他值检碗,那我們應(yīng)該怎么辦呢据块?
var stuPeking = new Student('Jerry',22);
stuPeking.school='Peking University';
console.log(stuPeking.school); // Peking University
console.log(stu1.school); // TsingHua
這里就涉及到原型鏈的概念。
原型鏈?zhǔn)谦@取屬性的先后順序:
.基本屬性 > .prototype.屬性名 > Object構(gòu)造函數(shù) > null
可以看到折剃,基本屬性的取值優(yōu)先級大于原型屬性另假,所以當(dāng)一個對象的 school 值不是'TsingHua',那我們可以把這個對象的 school 設(shè)置為基本屬性怕犁,那么它的優(yōu)先級就更高边篮,可以設(shè)置為我們預(yù)期的值己莺,就可以了。