1. 程式人生 > >js 的prototype 屬性和用法,外加__proto__ JavaScript中__proto__與prototype的關係

js 的prototype 屬性和用法,外加__proto__ JavaScript中__proto__與prototype的關係

var ob = { };//超級簡單的空物件
alert(JSON.stringify(ob.prototype));
// undefined

能夠引用prototype的東西絕對是函式,絕對是函式,絕對是函式,prototype是屬於函式的一個屬性,prototype是屬於函式的一個屬性,prototype是屬於函式的一個屬性,能夠引用它的只有·····函式····,能夠引用它的只有·····函式·····,能夠引用它的只有····函式····,函式,函式,函式,

prototype的應用

1.0 

給原型物件增加函式,就是讓物件擁有公用的函式。

例子:我給陣列原型物件增加一個打亂陣列的方法:

 //給陣列原型增加一個打亂陣列的函式

Array.prototype.shuffle = function(){
console.log(this)
let value = this.valueOf(),len = this.length,temp,key;
while(len--){
//隨機生成陣列的下標
key = Math.floor(Math.random()*len);
//temp為中間交換變數
temp = value[key];
value[key]=value[len]
value[len]=temp;
}
return value
}
let aa = ['1','2','3','4','5'];
console.log(aa.shuffle());
2.0
給原型物件增加屬性,也就是給物件增加公用的屬性
function fun(){

}  
fun。prototype.name = "小宋";
fun.prototype.arr = ['1','2'];
let a = new fun();
console.log(a.name)
3.0 最主要的屬性實現原型繼承
  
function P1(){

}
function P2(){

}
//原型物件增加屬性和方法
P1.prototype.name="鄭1"
P1.prototype.get = function(value){
return value
}
//例項化P2建構函式的一個物件
var o1 = new P1();//這個物件應該包含所有原型物件的屬性和方法
console.log(o1);
//給P2的原型物件賦值一個物件,相當於P1繼承了o1的所有屬性和方法
P2.prototype = o1;//這個式子,簡單來講就類似於a = b, b賦值給a這個總該明白吧?
    //呼叫P2從o1繼承過來的get函式
console.log(P2.prototype.get("123"));
//展示P2從o1繼承過來的name屬性
console.log(P2.prototype.name);
//用建構函式P2例項化一個o2物件
var o2 = new P2();
//P2的原型物件prototype既然已經繼承了o1的所有屬性和函式,那麼依據P2所例項化出來的物件也都有o1的屬性和函數了
console.log(o2)
console.log(o2.name)
console.log(o2.get('456789'))
Array.prototype是一個數組
String.prototype是一個字串
Object.prototype是一個物件


接下里有個疑問點是__proto__和arguments物件
prototype 是函式的一個屬性(每個函式都有一個prototype屬性),這個屬性時一個指標,
指標,指向一個物件,它是顯示修改物件的原型的屬性。
__proto__是一個物件的內建屬性(請注意:prototype是函式的內建屬性,__proto__是物件的內建屬性)
是js內部使用尋找原型鏈的屬性。
使用chrome和ff都可以訪問到__proto__屬性,ie不可以。
new 一個函式的過程得
var Person = function(){}
var p = new Person()
1.0 var p = {}
2.0 p.__proto__ = Person.prototype
3.0 Personal.call(p);也就是構造p,也可以稱之為初始化p
4.0 return p
我們console.log(p.__proto__===Person.prototype)
//返回的是true
我們再來一個demo
var person = function(){};
persona.prototype.sayName = function(){
  console.log("my name is body")
}
person.prototype.age = 27;
var p = new person();
p.sayName();
p是一個引用指向person物件,我們在persona的原型商店一了一個sayName
方法和age屬性,當我們執行p.age時,會先在this的內部查詢(也就是建構函式內部)
,如果沒有知道然後再沿著原型鏈向上追溯,這裡的向上追溯是怎麼向上的呢?這裡就要使用
__proto__屬性來連結到原型(也就是Personal.prototype)進行查詢.最終在原型上找到了age。
js中_proto_和 prototype的區別和聯絡、
首先要明確兩點
1.0 在js裡,也是萬物皆物件,方法(Function)是物件,方法的原型(Function.prototype)
是物件,因此,他們都會具有物件共有的特點。
既:物件具有屬性__proto__,可稱為隱式原型,一個物件的隱式原型指向建構函式的原型這
這保證了例項能夠訪問在建構函式原型中定義的屬性和方法
2.0,方法(Function)
方法這個特殊的物件,除了和其他物件一樣有上述__proto__屬性之外,還有自己的特有屬性
--原型屬性(prototype),這個屬性是一個指標,指向一個物件,這個物件的用途就是包含
所有例項共享的屬性和方法(我們把這個物件叫原型物件),原型物件也有一個屬性,叫做
constructor,這個屬性包含了一個指標,指回原建構函式。
function Foo(){}
var f1 = new Foo();
var f2 = new Foo();
1.0 建構函式Foo()
建構函式的原型屬性Foo.prototype指向了原型物件,在原型物件裡有共有的
方法,所有建構函式宣告的例項(f1,f2)都可以共享這個方法。
2.0 原型物件Foo.prototype
Foo.prototype儲存著例項共享的方法,有一個指標constructor指回建構函式。
3.0 例項
f1和f2是Foo這個物件的兩個例項,這兩個物件也有屬性__proto__,指
向建構函式的原型物件,這樣子就可以像上面1所說的訪問原型物件的所有
方法和屬性了。
另外:
建構函式Foo()出來是方法,也是物件,他也有__proto__屬性,指向誰呢?
指向它的建構函式的原型物件,函式的建構函式時function,因此這裡的__proto__指向Function.prototype
其實出來Foo(),Function(),Object()也是一樣的道理
原型物件也是物件啊,它的__proto__屬性,又指向誰呢?
同理,指向它的建構函式的原型物件,這裡是Object.prototype
最後,Object.prototype的__proto__屬性指向null。
總結:
1.0 物件有屬性__proto__,指向該物件的建構函式的原型物件。
2.0 方法除了有屬性__proto__,還有屬性prototype,prototype指向該方法的原型物件。

JavaScript中__proto__與prototype的關係

這裡討論下物件的內部原型(__proto__)和構造器的原型(prototype)的關係。

所有構造器/函式的__proto__都指向Function.prototype,它是一個空函式(Empty function)

 
 
  
  
1 2 3 4 5 6 7 8 9 Number.__proto__ === Function.prototype   // true Boolean.__proto__ === Function.prototype  // true String.__proto__ === Function.prototype   // true Object.__proto__ === Function.prototype   // true Function.__proto__ === Function.prototype  // true Array.__proto__ === Function.prototype    // true RegExp.__proto__ === Function.prototype   // true Error.__proto__ === Function.prototype    // true Date.__proto__ === Function.prototype     // true
 

JavaScript中有內建(build-in)構造器/物件共計12個(ES5中新加了JSON),這裡列舉了可訪問的8個構造器。剩下如Global不能直接訪問,Arguments僅在函式呼叫時由JS引擎建立,Math,JSON是以物件形式存在的,無需new。它們的__proto__是Object.prototype。如下

 
 
  
  
1 2 Math.__proto__ === Object.prototype   // true JSON.__proto__ === Object.prototype   // true
這個內建的,我看了有人說9個有人說12個,我認為是9個

這說明什麼呢?

 

所有的構造器都來自於Function.prototype,甚至包括根構造器Object及Function自身。所有構造器都繼承了Function.prototype的屬性及方法。如length、call、apply、bind(ES5)。

Function.prototype也是唯一一個typeof XXX.prototype為 “function”的prototype。其它的構造器的prototype都是一個物件。如下

1 2 3 4 5 6 7 8 9 10 console.log( typeof  Function.prototype)  // function console.log( typeof  Object.prototype)    // object console.log( typeof  Number.prototype)    // object console.log( typeof  Boolean.prototype)   // object console.log( typeof  String.prototype)    // object console.log( typeof  Array.prototype)     // object console.log( typeof  RegExp.prototype)    // object console.log( typeof  Error.prototype)     // object console.log( typeof  Date.prototype)      // object console.log( typeof  Object.prototype)    // object

  

噢,上面還提到它是一個空的函式,alert(Function.prototype) 下看看。

 

知道了所有構造器(含內建及自定義)的__proto__都是Function.prototype,那Function.prototype的__proto__是誰呢?

 

相信都聽說過JavaScript中函式也是一等公民,那從哪能體現呢?如下

1 console.log(Function.prototype.__proto__ === Object.prototype)  // true

這說明所有的構造器也都是一個普通JS物件,可以給構造器新增/刪除屬性等。同時它也繼承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。

 

最後Object.prototype的__proto__是誰?

1 Object.prototype.__proto__ ===  null   // true

已經到頂了,為null。

二、所有物件的__proto__都指向其構造器的prototype

上面測試了所有內建構造器及自定義構造器的__proto__,下面再看看所有這些構造器的例項物件的__proto__指向誰?

 

先看看JavaScript引擎內建構造器

1 2 3 4 5 6 7 8 9 10 11 var  obj = {name:  'jack' } var  arr = [1,2,3] var  reg = /hello/g var  date =  new  Date var  err =  new  Error( 'exception' )   console.log(obj.__proto__ === Object.prototype)  // true console.log(arr.__proto__ === Array.prototype)   // true console.log(reg.__proto__ === RegExp.prototype)  // true console.log(date.__proto__ === Date.prototype)   // true console.log(err.__proto__ === Error.prototype)   // true

 

再看看自定義的構造器,這裡定義了一個Person

1 2 3 4 5 function  Person(name) {      this .name = name } var  p =  new  Person( 'jack' ) console.log(p.__proto__ === Person.prototype)  // true

p是Person的例項物件,p的內部原型總是指向其構造器Person的prototype。

 

每個物件都有一個constructor屬性,可以獲取它的構造器,因此以下列印結果也是恆等的

1 2 3 4 5 function  Person(name) {      this .name = name } var  p =  new  Person( 'jack' ) console.log(p.__proto__ === p.constructor.prototype)  // true

 

上面的Person沒有給其原型新增屬性或方法,這裡給其原型新增一個getName方法

1 2 3 4 5 6 7 8 function  Person(name) {      this .name = name } // 修改原型 Person.prototype.getName =  function () {} var  p =  new  Person( 'jack' ) console.log(p.__proto__ === Person.prototype)  // true console.log(p.__proto__ === p.constructor.prototype)  // true

可以看到p.__proto__與Person.prototype,p.constructor.prototype都是恆等的,即都指向同一個物件。

 

這個是個重點啊!

如果換一種方式設定原型,結果就有些不同了

1 2 3 4 5 6 7 8 9 10 function  Person(name) {      this .name = name } // 重寫原型 Person.prototype = {      getName:  function () {} } var  p =  new  Person( 'jack' ) console.log(p.__proto__ === Person.prototype)  // true console.log(p.__proto__ === p.constructor.prototype)  // false

這裡直接重寫了Person.prototype(注意:上一個示例是修改原型)。輸出結果可以看出p.__proto__仍然指向的是Person.prototype,而不是p.constructor.prototype。

這也很好理解,給Person.prototype賦值的是一個物件直接量{getName: function(){}},使用物件直接量方式定義的物件其構造器(constructor)指向的是根構造器Object,Object.prototype是一個空物件{},{}自然與{getName: function(){}}不等。如下

1 2 3 4 var  p = {} console.log(Object.prototype)  // 為一個空的物件{} console.log(p.constructor === Object)  // 物件直接量方式定義的物件其constructor為Object console.log(p.constructor.prototype === Object.prototype)  // 為true,不解釋 

 

上面程式碼中用到的__proto__目前在IE6/7/8/9中都不支援。IE9中可以使用Object.getPrototypeOf(ES5)獲取物件的內部原型。

1 2 3 var  p = {} var  __proto__ = Object.getPrototypeOf(p) console.log(__proto__ === Object.prototype)  // true
 

物件字面量表示法是首選的建構函式

 

JavaScript語言九種內建的構造器:Object()Array()String()Number()Boolean()Date()Function()Error() 以及 RegExp()。當我們需要建立這些值的時候,我們可以自由選擇使用字面量或者構造器。但是相同情況下,字面量物件不僅易讀,而且執行速度更快,因為他們可以在解析的時候被優化。所以當你需要使用簡單物件的時候就使用字面量吧。