昨天看對原型概念有了一點點的興趣,雖說了解的不是很透徹,但是還是多多少少有一點收穫的,就自己的一些學習到的東西做一個小小的總結。主要是結合了課本、網上資源和一些視頻來學習的。
原型涉及到了原型、原型鏈和構造函數。而且在每個博客的講解中都涉及到了構造函數的內容,那就先從構造函數的概念和作用談起。
構造函數
構造函數我們應該都很清楚了,在學習C#的時候接觸過這個概念。在JS的學習中:構造函數的特點:
a:構造函數的首字母必須大寫,用來區分於普通函數
b:內部使用的this對象,來指向即將要生成的實例對象
c:使用New來生成實例對象
例如:
//構造函數
function Person(name,age){
this.name = name;
this.age = age;
this.sayHello = function(){
console.log(this.name +"say hello");
}
}
var boy = new Person("bella",23);
boy.sayHello(); // bella say hello
構造函數的缺點:
所有的實例對象都可以繼承構造器函數中的屬性和方法。但是,同一個對象實例之間,無法共享屬性
解決思路:
a:所有實例都會通過原型鏈引用到prototype
b:prototype相當於特定類型所有實例都可以訪問到的一個公共容器
c:那麼我們就將重複的東西放到公共容易就好了
如下顯示:
function Person(name,age){
this.name = name;
this.age = age;
this.sayHello = function(){
console.log(this.name + "say hello");
}
}
var girl = new Person("bella",23);
var boy = new Person("alex",23);
console.log(girl.name); //bella
console.log(boy.name); //alex
console.log(girl.sayHello === boy.sayHello); //false
原型
prototype(原型):是function對象的一個熟悉性,定義了構造函數製造出的對象的公共祖先(公共屬性和方法)通過構造函數產生對象,可以繼承改變原型的屬性和方法。原型也是對象。
__proto__(隱士原型):每個對象的__proto__屬性指向自身構造函數的prototype;
constructor(構造器):返回對創建此對象的數組函數的作用。
prototype屬性的作用
js中每個數據類型都是對象,除了null 和 undefined,而每個對象都是繼承自一個原型對象,只有null除外,它沒有自己的原型對象,最終的Object的原型爲null
function Person(name,age){
this.name = name;
this.age = age;
}
Person.propotype.sayHello = function(){
console.log(this.name + "say hello");
}
var girl = new Person("bella",23);
var boy = new Person("alex",23);
console.log(girl.name); //bella
console.log(boy.name); //alex
console.log(girl.sayHello === boy.sayHello); //true
由上圖可以看出,prototype是構造函數的屬性,而consructor則是構造函數的prototype屬性所指向的那個對象,也就是說constuctor是原型對象的屬性。
constructor屬性是定義在原型對象上面,意味着也可以被實例對象繼承。
- 如果有原型,那麼就一定有函數。每一個對象有一個屬性叫__proto__;這個屬性就是對象的原型。對象有原型,那麼原型也是對象,原型也有原型。
- 所有的函數是對象,繼承自Function.prototype
- Function.prototype是對象,繼承自Object.prototype
- Object.prototype是對象,繼承自null
- obj是對象,繼承自Object.prototype
- Function是對象,繼承自Function.prototype
- Function是函數,繼承自Function.prototype
這就涉及到了原型鏈。
原型鏈
首先看一段代碼:
<!DOCTYPE html>
<html>
<head>
<title></title>
<style type="text/css">
</style>
<script type="text/javascript">
var o = {}; //{ name:"我是祖宗"};
var f1 = function() {
// this.name = "我是亞當";
};
f1.prototype=o;
var foo1 = new f1();
var f2 = function() {
// this.name = "夏娃";
}
var foo2 = new f2();
foo2.__proto__ = foo1;
var f3 = function() {
// this.name = "我是人類";
};
f3.prototype = foo2;
var foo3 = new f3();
alert(foo3.name);
</script>
</head>
<body>
</body>
</html>
上面代碼的運行結果:
1)當所有的this.name,都沒有註釋的話:運行結果----》我是人類
2)當f3的this.name 註釋掉,運行結果-----》我是夏娃
3)當f2和f3中的this.name註釋,運行結果是-----》我是亞當
4)當f1,f2,f3中的this.name註釋,運行結果----》我是祖宗,
5)當全部被註釋掉,運行結果是undefined;
js成員的訪問規則
- o.方法()
- 首先在o當前這個類型中尋找該成員的定義,如果存在該成員的定義
- 那麼就直接使用改成員
- 如果該成員不再當前類型中,就訪問其原型(原型鏈中的上一級)
- 以此類推,直到null位置
上圖中的原型鏈:
對象 | __proto__ | prototype |
constructor |
foo | Foo.prototype | --- | --- |
obj | Object.prototype | --- | --- |
Foo | Function.prototype | Foo.prototype | |
Foo.prototype | Object.prototype | --- | Foo |
Function | Function.prototype | Function.prototype | |
Function.Prototype | Object.prototype | --- | Function |
obj | Object.prototype | --- | --- |
Object | Function.prototype | Object.prototype | --- |
Object.prototype | null | --- | Object |
參考鏈接: