普通對象和函數(shù)對象
函數(shù)對象:使用函數(shù)聲明
类早、函數(shù)表達式
、Function構(gòu)造函數(shù)
創(chuàng)建的對象
函數(shù)實際上是對象嗜逻,每個函數(shù)都是
Function
類型的實例涩僻,而且都與其他引用類型一樣具有屬性和方法。
普通對象:除了函數(shù)對象
以外的對象栈顷,都是普通對象逆日。
示例:
// 定義函數(shù)的三個方法
function f1() {}; // 函數(shù)聲明
var f2 = function() {}; // 函數(shù)表達式
var f3 = new Function("num1", "num2", "return num1 + num2"); // Function構(gòu)造函數(shù)
// 創(chuàng)建對象
var o1 = {}; // 對象字面量
var o2 = new Object(); // Object構(gòu)造函數(shù)
var o3 = new f1(); // f1構(gòu)造函數(shù)
// 檢測類型
console.log(typeof Function); //function
console.log(typeof Object); //function
console.log(typeof f1); //function
console.log(typeof f2); //function
console.log(typeof f3); //function
console.log(typeof o1); //object
console.log(typeof o2); //object
console.log(typeof o3); //object
構(gòu)造函數(shù)
構(gòu)造函數(shù): 通過new
關(guān)鍵字方式調(diào)用的函數(shù)。
在構(gòu)造函數(shù)內(nèi)部(也就是被調(diào)用的函數(shù)內(nèi)):
-
this
指向?qū)嵗龑ο?Object
萄凤; - 這個實例對象的
__proto__
屬性指向構(gòu)造函數(shù)的prototype
室抽; - 這個實例對象的
constructor
屬性指向構(gòu)造函數(shù)
; - 如果被調(diào)用的函數(shù)沒有顯式的 return 表達式靡努,則隱式的會返回 this 對象 —— 也就是實例對象坪圾。
示例:
function Person(name) {
this.name = name;
this.sayName = function() {
console.log(this.name);
};
}
var person1 = new Person("Hysunny");
var person2 = new Person("Max");
console.log(person1 instanceof Person); // true
console.log(person1.constructor === person2.constructor); // true
// 實例的__proto__屬性指向構(gòu)造函數(shù)的prototype
console.log(person1.__proto__ === Person.prototype); // true
// 實例的constructor指向構(gòu)造函數(shù)
console.log(person1.constructor === Person); // true
原型對象
在 JavaScript 中,每當(dāng)定義一個對象(函數(shù))時候颤难,對象中都會包含一些預(yù)定義的屬性。其中就包含prototype
屬性已维,這個屬性指向函數(shù)的原型對象
行嗤。
- 原型對象是一個
普通對象
(除Function.prototype
之外),存儲所有實例對象共享的方法和屬性垛耳; - 構(gòu)造函數(shù)原型對象是
構(gòu)造函數(shù)
的一個實例栅屏。 - 原型對象的
constructor
屬性指向prototype
屬性所在的函數(shù); - 每個對象都有
__proto__
屬性堂鲜,但只有函數(shù)對象才有prototype
屬性栈雳,這兩個屬性指向函數(shù)的原型對象。
示例:
function Person(name) {
this.name = name;
}
Person.prototype. sayName = function() {
console.log(this.name);
}
var person1 = new Person("Hysunny");
var person2 = new Person("Max");
// 構(gòu)造函數(shù)缔莲、原型對象和實例之間有這樣的聯(lián)系
Person.prototype.constructor === Person;
person1.__proto__ === Person.prototype;
person1.constructor === Person;
console.log(person1.constructor === Person); // true
console.log(Person.prototype.constructor === Person); // true
console.log(Person.prototype.constructor === person1.constructor); // true
// => 原型對象是構(gòu)造函數(shù)的一個實例
console.log(Person.prototype.constructor == Person); // true
// => 原型對象的constructor屬性指向prototype屬性所在的函數(shù)
console.log(person1.__proto__ === Person.prototype); // true
// => __proto__屬性指向函數(shù)的原型對象
注: Function.prototype
雖為函數(shù)對象哥纫,但是是個空函數(shù),沒有prototype
屬性痴奏。
console.log(typeof Function.prototype) // function
console.log(typeof Function.prototype.prototype) // undefined
原型鏈
從上面的分析我們可以知道:JS在創(chuàng)建對象(不論是普通對象還是函數(shù)對象)的時候蛀骇,都有一個__proto__
內(nèi)置屬性厌秒,用于指向創(chuàng)建它的函數(shù)對象的原型對象prototype
。
以上面的例子為例:
-
person1
具有__proto__
屬性擅憔,指向Person.prototype
-
Person.prototype
具有__proto__
屬性鸵闪,指向Object.prototype
-
Object.prototype
具有__proto__
屬性,指向null
console.log(person1.__proto__ === Person.prototype) // true
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Object.prototype.__proto__) // null
這些__proto__
串起來暑诸,就構(gòu)成了原型鏈蚌讼,原型鏈的頂端為null
。繪出原型鏈圖如下:
簡化如下:
疑點解釋:
1. Object.__proto__ === Function.prototype // true
// Object是函數(shù)對象个榕,是通過new Function()創(chuàng)建篡石,所以O(shè)bject.__proto__指向Function.prototype。
2. Function.__proto__ === Function.prototype // true
// Function 也是對象函數(shù)笛洛,也是通過new Function()創(chuàng)建夏志,所以Function.__proto__指向Function.prototype。
3. Function.prototype.__proto__ === Object.prototype // true
// Function本身也是一個構(gòu)造函數(shù)苛让,所以`Function.prototype.__proto__`指向`Object.prototype`
繼承
繼承是OO語言中的一個最為人津津樂道的概念.許多OO語言都支持兩種繼承方式:
接口繼承
和實現(xiàn)繼承
沟蔑。接口繼承只繼承方法簽名,而實現(xiàn)繼承則繼承實際的方法.由于js中方法沒有簽名,在ECMAScript中無法實現(xiàn)接口繼承.ECMAScript只支持實現(xiàn)繼承,而且其實現(xiàn)繼承
主要是依靠原型鏈來實現(xiàn)的.
為什么要實現(xiàn)繼承呢?
最重要的原因之一就是為了抽象(復(fù)用代碼)
狱杰。
將公共的代碼封裝成一個基類瘦材,其他子類繼承基類,并發(fā)展自己特有的屬性和樣式仿畸。
關(guān)于實現(xiàn)繼承
的方式食棕,我們將在下一篇文章中進行討論。
參考資料:
《JavaScript 高級程序設(shè)計》 第三版