JS 的面向對象特性
一. 概念
- 類:有相同的特征和行為的事物的抽象
- 對象:類的一個實例
面向對象語言的要求:
一種面向對象語言需要向開發者提供四種基本能力:
封裝 - 把相關的信息(無論數據或方法)存儲在對象中的能力
聚集 - 把一個對象存儲在另一個對象內的能力
繼承 - 由另一個類(或多個類)得來類的屬性和方法的能力
多態 - 編寫能以多種方法運行的函數或方法的能力
————————————————W3C:ECMAScript 面向對象技術
ECMAScript 支持這些要求,因此可被是看做面向對象的。
但是 JS 中沒有類的概念,而且繼承等的方式非常復雜且無用,所以我們也說 JS 不是一個嚴格面向對象的語言。
二. 對象的判斷
對于判斷一個變量是否是對象,我們通常選擇兩個方式。
1. typeOf
typeOf 運算符有一個參數,即要檢查的變量或者值。返回值就是這個變量或者值的類型。
console.log(typeof 12); // number 數字類型
console.log(typeof 'qweqwe'); // sting 字符串類型
console.log(typeof true); // boolean 布爾類型
var fn = function() {};
console.log(typeof fn); // function 函數類型
var arr = [1, 2, 'lalala'];
console.log(typeof arr); // object 引用類型
//object 引用類型 不叫對象類型
另外還存在 undefined 類型。
2. instanceof
instanceof 方法有兩個參數:第一個是要比較的變量或者值,第二個是變量類型,返回的值是 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
三. 如何創建一個對象
這里有兩個創建對象方式:
1. 直接創建
var 變量名={
屬性1:值1,
屬性2:值2,
... ...
函數名: function(){
函數內容
}
}
舉例:
var stu = {
name: 'Tom',
age: 42,
sex: 'female',
sayHi: function() {
console.log(this.name)
}
};
此時我們就創建了一個名為 stu 的對象,這個對象包括三個屬性:name, age, sex。
console.log(stu.age); // 42
同時對象可以自己調用自己內部的函數:
stu.sayHi(); // Tom
2. 對象的構造函數
在第一種直接創建方式中,我們可以想象,如果要批量創建對象,會很繁瑣。所以我們可以創建一個函數,進行對象的創建。
結構:
function 構造函數名(參數1,參數2,...){
this.屬性1 = 參數1;
this.屬性2 = 參數2;
... ...
this.函數名= function(){
函數內容
}
}
舉例:
function Student(name, age) {
this.name = name;
this.age = age;
this.sayHi = function() {
console.log("i'm " + this.name);
};
};
此時我們就有了一個可以創建對象的函數,我們只要輸入對應的參數值,就可以得到有函數內包含的屬性的對象。
那么我們用構造函數來創建對象:
var stu1 = new Student('Tom', 42);
console.log(stu1.name); // Tom
stu1.sayHi(); // i'm Tom
構造函數創建對象有如下的優點:
- 創建對象,將復雜的內容簡化為一個函數
- 改動方便,改函數,改所有對象
四. 原型
1. 概念
每一個構造函數創建的屬性都遠原型屬性,當我們在某一個對象內創建一個原型屬性,這個屬性就被曝存在了一個獨立于每個對象空間的堵路區域,且可以被所有對象訪問到。
2. 原型的基本設置方式
Student.prototype.school = 'TsingHua';
// 此時我們就創建了一個原型屬性school,而且屬性的值都是一樣的,是TsingHua
// 這個屬性可以被所有對象訪問到
console.log(stu1.school); // TsingHua
同時原型屬性也可以是函數
Student.prototype.saySchool = function() {
console.log('我的老家就在這個' + this.school);
console.log(this);
};
stu1.saySchool();
// 我的老家就在這個TsingHua
// Student {name: "Tom", age: 42}
3. 屬性獲取順序(原型鏈)
那么,如果此時有一個對象的 school 是其他值,那我們應該怎么辦呢?
var stuPeking = new Student('Jerry',22);
stuPeking.school='Peking University';
console.log(stuPeking.school); // Peking University
console.log(stu1.school); // TsingHua
這里就涉及到原型鏈的概念。
原型鏈是獲取屬性的先后順序:
.基本屬性 > .prototype.屬性名 > Object構造函數 > null
可以看到,基本屬性的取值優先級大于原型屬性,所以當一個對象的 school 值不是'TsingHua',那我們可以把這個對象的 school 設置為基本屬性,那么它的優先級就更高,可以設置為我們預期的值,就可以了。