Object.prototype 原型和原型鏈
原型
Javascript中所有的對象都是Object的實例,並繼承Object.prototype的屬性和方法,有些屬性是隱藏的。換句話說,在對象創建時會存在預定義的屬性,其中有一個屬性就是原型對象。在函數對象中存在原型對象prototype,在普通對象中沒有prototype
,但存在__proto__
。或者說使用function定義的對象與使用new操作符生成的對象之間有一個重要的區別,這個區別就是function定義的對象有一個prototype屬性,使用new生成的對象就沒有這個prototype屬性,存在__proto__
。
var o =new Object();
console.log(o.__proto__);
console.log(o.prototype);//undefined
var fn = function(){}
console.log(fn.prototype);//Object {constructor: function}
var f1 = new fn();
console.log(f1.__proto__);
console.log(f1.__proto__===fn.prototype);//true
原型鏈
那么__proto__
是什么?每個對象都會在其內部初始化一個屬性,就是__proto__
。
普通對象中的__proto__
是什么呢? Object的本質函數對象,是通過new Function()創建,所以Object.__proto__
指向Function.prototype
。同理,Function也是函數對象,因此Function.__proto__
同樣指向Function.prototype
。 Object.prototype
對象也有__proto__
屬性,但它比較特殊,為null。這個由__proto__
串起來的直到Object.prototype.__proto__
為null的鏈就是原型鏈。
console.log(Object.__proto__ === Function.prototype);//true
console.log(Function.__proto__===Function.prototype);//true
console.log(Object.prototype.__proto__);//null
當我們訪問一個對象的屬性 時,如果這個對象內部不存在這個屬性,那么他就會去__proto__
里找這個屬性,這個__proto__
又會有自己的__proto__
,於是就這樣 一直找下去,也就是我們平時所說的原型鏈的概念。參考下面的例子:
var Fn = function(){};
Fn.prototype.Hello = function(){
console.log("Hello World");
}
var f1 = new Fn();
f1.Hello();//Hello World
首先var f1=new fn(),f1是Fn的實例,可以得出f1.__proto__=Fn.prototype
。當我們調用f1.hello()
時,首先f1中沒有Hello
這個屬性,於是,它會到他的__proto__
中去找,也就是Fn.prototype
,而我們在上面定義了 Fn.prototype.Hello=function(){}; 於是,就找到了對應的方法。
從一個更復雜的例子中看原型鏈的原理:
var Person = function() {};
Person.prototype.Name = function() {
console.log("person name");
}
Person.prototype.Sex = "male or female";
var Younger = function() {};
Younger.prototype = new Person();
Younger.prototype.Age = function() {
console.log("14-28")
};
Younger.prototype.Sex = "female";
var Ann = new Younger();
Ann.Name(); //person name
console.log(Ann.Age()); //14-28
console.log(Ann.Sex); //female
對上述代碼,我們可以進行如下分析:
var Younger = function() {}
=>:Younger.__proto__=Person.prototype
,
Younger.prototype = new Person()
=>:Younger.prototype.__proto__ = Person.prototype
,
var Ann = new Younger()
===>Ann.__proto__=Younger.prototype
,
綜上可得:
Ann.__proto__.__proto__ = Person.prototype
Ann
本身沒有Name()
方法,於是從Ann.__proto__
(Younger.prototype
)中找,仍沒有找到於是在向上一層Ann.__proto__.__proto__
(Person.prototype
)中尋找,最終在Person.prototype
中找到對應的方法並調用。
同理,Ann
本身並沒有Age()
方法,但在Ann.__proto__
(Younger.prototype
)存在。
對於Ann.Sex
,在Ann.__proto__
(Younger.prototype
)中已經能夠找到,便不再向上尋找,因此輸出是female
。