prototype、constructor那點事兒

1、什麼是原型(prototype)數組

  一、prototype本質上仍是一個JavaScript對象;函數

  二、每一個函數都有一個默認的prototype屬性;this

  三、經過prototype咱們能夠擴展Javascript的內建對象spa


若是這個函數被用在建立自定義對象的場景中,咱們稱這個函數爲構造函數。 好比:prototype

 

代碼
// 構造函數
function Person(name) {
this .name = name;
}
// 定義Person的原型,原型中的屬性能夠被自定義對象引用
Person.prototype = {getName: function () {
return this .name;
}};
var zhang = new Person( " ZhangSan " );
console.log(zhang.getName());
// "ZhangSan"

咱們能夠經過prototype擴展Javascript的內建對象,例如:code

 

 

代碼
// 向JavaScript固有類型Array擴展一個獲取最小值的方法
Array.prototype.min = function () {
var min = this [ 0 ];
for ( var i = 1 ; i < this .length; i ++ ) {
if ( this [i] < min) {
min
= this [i];
}
}
return min;
};

// 在任意Array的實例上調用min方法
console.log([ 1 , 56 , 34 , 12 ].min()); // 1

 

注意:這裏有一個陷阱,向Array的原型中添加擴展方法後,當使用for-in循環數組時,這個擴展方法也會被循環出來。對象

下面的代碼說明這一點(假設已經向Array的原型中擴展了min方法):blog

 

var arr = [ 1 , 56 , 34 , 12 ];
var total = 0 ;
for ( var i in arr) {
total
+= parseInt(arr[i], 10 );
}
console.log(total);
// NaN

 

解決方法也很簡單:ip

 

var arr = [ 1 , 56 , 34 , 12 ];
var total = 0 ;
for ( var i in arr) {
if (arr.hasOwnProperty(i)) {
total
+= parseInt(arr[i], 10 );
}
}
console.log(total);
// 103

 

2、構造器(constructor)get

    一、constructor始終指向建立當前對象的構造(初始化)函數。
    二、每一個函數都有一個默認的屬性prototype,而這個prototype的constructor默認指向這個函數


咱們來看個例子:

 

代碼
// 等價於 var arr = new Array(1, 56, 34, 12);
var arr = [ 1 , 56 , 34 , 12 ];
console.log(arr.constructor
=== Array); // true
//
等價於 var foo = new Function();
var Foo = function () {
};
console.log(Foo.constructor
=== Function); // true
//
由構造函數實例化一個obj對象
var obj = new Foo();
console.log(obj.constructor
=== Foo); // true

// 將上面兩段代碼合起來,就獲得下面的結論
console.log(obj.constructor.constructor === Function); // true

可是當constructor遇到prototype時,有趣的事情就發生了。
咱們知道每一個函數都有一個默認的屬性prototype,而這個prototype的constructor默認指向這個函數。以下例所示:

 

代碼
function Person(name) {
this .name = name;
}
Person.prototype.getName
= function () {
return this .name;
};
var p = new Person( " ZhangSan " );
console.log(p.constructor
=== Person); // true
console.log(Person.prototype.constructor === Person); // true
//
將上兩行代碼合併就獲得以下結果
console.log(p.constructor.prototype.constructor === Person); // true

當時當咱們從新定義函數的prototype時(注意:和上例的區別,這裏不是修改而是覆蓋), constructor的行爲就有點奇怪了,以下示例

 

代碼
function Person(name) {

this .name = name;
}
Person.prototype
= {getName: function () {
return this .name;
}};
var p = new Person( " ZhangSan " );
console.log(p.constructor
=== Person); // false
console.log(Person.prototype.constructor === Person); // false
console.log(p.constructor.prototype.constructor === Person); // false

爲何呢?
原來是由於覆蓋Person.prototype時,等價於進行以下代碼操做:

 

 

Person.prototype = new Object({getName: function () {
return this .name;
}});

而constructor始終指向建立自身的構造函數,因此此時Person.prototype.constructor === Object

 

怎麼修正這種問題呢?方法也很簡單,從新覆蓋Person.prototype.constructor便可:

 

代碼
function Person(name) {
this .name = name;
}
Person.prototype
= new Object({getName: function () {
return this .name;
}});
Person.prototype.constructor
= Person;
var p = new Person( " ZhangSan " );
console.log(p.constructor
=== Person); // true
console.log(Person.prototype.constructor === Person); // true
console.log(p.constructor.prototype.constructor === Person); // true
相關文章
相關標籤/搜索