JavaScript的原型鏈繼承__propt__、prototype、constructor的理解、以及他們之間相互的關係。

回想本身已經工做了有一段時間了,可是本身對JavaScript的原型鏈、和繼承的理解能力沒有到位,最近他們完全的整理而且複習了一遍。javascript

本案例中部分文案來自網絡和書籍,若有侵權請聯繫我,我只是把個人理解和想法告訴你們。java

本着互聯網分享精神、如今我就將個人學習以及理解分享給你們。若是那裏又說的不對的地方請私信我,我會及時回覆。c++

建立一個構造函數- 案例一

講解:不少人見到了久違的new操做符,因而就叫Person爲「類」,但是又沒有關鍵字class的出現,以爲叫「類」有點勉強。因而退而求其次叫Person爲類的構造函數。這些概念好像都沒有錯,之因此出現這樣的狀況,多是由於你們都學習了傳統的面嚮對象語言(c++,c#,Java等),還有一種思惟定勢吧。爲了讓javascript也面向對象,要在javascript中找到與傳統面嚮對象語言的影子。但是按照javascript的說法,function定義的這個Person就是一個Object(對象),並且仍是一個很特殊的對象,這個使用function定義的對象與使用new操做符生成的對象之間有一個重要的區別。這個區別就是function定義的對象有一個prototype屬性,使用new生成的對象就沒有這個prototype屬性。c#

function Person(name) {
    this.name = name;
    this.showMe = function () {
        console.log(this.name);
    }
};

var per= new Person('鉛筆')  //實例化這個構造函數

per.showMe()   //執行函數內部的方法

 prototype講解- 案例二

講解:在上面的案例中已經說到了,function定義的函數是一個特殊對象,他擁有prototype屬性。prototype屬性能夠在對象的原型中添加原型方法。網絡

請看代碼函數

function Person(name) {
    this.name = name;
    this.showMe = function () {
        console.log(this.name);
    }
};
Person.prototype.user = function (user) {  // 向原型中添加原型方法
    return user
};
Person.prototype.age = 23;    // 像原型中添加屬性,而且賦值,
var one = new Person('js');  // 實例化方法。

console.log(one.user('這是原型對象'));  //調用實例化方法的方法
console.log(one.age);  //調用實例化方法的屬性

案例二的代碼中,爲何能夠調用Person的pertotype方法呢。這就要講到Peron在實例化時候發生的事情。學習

第一件事情:創建了一個one對象。(能夠理解爲 var one={})this

第二件事情:將one對象的內置原型對象(__proto__)設置爲構造函數person的prototype屬性所引用的那個原型對象。(能夠理解爲:one.__proto__ = Person.prototype; 這個__proto__稍後再講)spa

第三件事:將one對象做爲this參數調用構造函數person(能夠理解爲var one={ Person.call(this}; 也就至關於當前對象擁有了Person中全部的屬性和方法)prototype

這樣就能夠理解爲何one能夠直接調用proson的pertotype方法了。

constructor講解-案例三

在prototype對象中又有一個constructor屬性,這個constructor屬性一樣指向一個constructor對象,而這個constructor對象偏偏就是這個function函數自己(Person)。

function Person(name) {
    this.name = name;
    this.showMe = function () {
        alert(this.name);
    }
};

var one = new Person('js');
alert(one.prototype)//undefined  
alert(typeof Person.prototype);//object  
alert(Person.prototype.constructor);//function Person(name) {...};  

以上三案例是否是看着有點暈了,其實沒那麼複雜,直接上圖。

 

__proto__原型鏈講解-案例四

在案列二中講到每個函數都有一個protytype屬性,而對象卻沒有,可是對象有一個__propt__內置屬性,而且這個屬性是包含對指定對象的內部原型的引用。原型鏈上的對象正是依靠這個__proto__屬性連結在一塊兒的。注意函數本質也是對象並且是特殊對象,因此函數也有__propt__屬性。

function Person(name) {
    this.name = name;
    this.showMe = function () {
        console.log(this.name);
    }
};

Person.prototype.from = function () {
    console.log('I come from prototype.');
}

var per = new Person('js');
console.log(per.__proto__)  //輸出 Person { from: [Function] }

 在舉一個原型鏈的例子

var Person = function() {};
Person.prototype.say = function() {
    console.log("Person say");
};
Person.prototype.salary = 50000;

var Programmer = function() {};
Programmer.prototype = new Person();
Programmer.prototype.writeCode = function() {
    console.log("Programmer writes code");
};

var p = new Programmer();
p.say(); // Person say
p.writeCode(); // Programmer writes code
console.log(p.salary); // 50000
console.log(p.__proto__)  // Person { writeCode: [Function] }
console.log(p.__proto__.__proto__)  //Person { say: [Function], salary: 50000 }   看沒看到,這裏纔有salary和say方法  這就是原型鏈,直到找到這個方法爲止。
console.log(p.__proto__.__proto__.__proto__)  // {}   __proto__會一直向上查找,直到{}纔會中止,此刻就會證實沒有找到方法或屬性。到頭了呀親、

原型鏈上圖。唉圖畫的好累啊。

 

 

在舉一個修改__proto__指向的例子

function Person(name) {
    this.name = name;
    this.showMe = function () {
        console.log(this.name);
    }
}
Person.prototype.from = function () {
    console.log('I come from prototype.');
};
function SubPer() {
    this.tests = function () {
        console.log('tst')
    }
}
var son = new SubPer();
console.log(son.__proto__);  //SubPer {}
son.tests();
// son.from()   //此刻會報錯
son.__proto__ = new Person('name');  //修改son實例對象的prototype原型對象的引用
console.log(son.__proto__);  // Person { name: undefined, showMe: [Function] }
son.showMe()      //name
son.tests();   //此方法會被調用,由於SubPer函數內自身就有 tests 函數。
son.from();   //此刻會調用Person原型對象方法,由於更改了son實例對象的prototype原型對象的引用。

 使用hasOwnProperty判斷屬性是自身的仍是原型鏈上的。

在JavaScript的對象中有這樣一個神奇的方法hasOwnProperty,他能夠判斷該方法或屬性是對象自身的仍是原型鏈上的,廢話很少說直接上代碼。

function a(name) {
    this.name = name;
    this.showName = function () {
        console.log(this.name)
    }
}
function b(name) {
    this.name = name;
    this.showName = function () {
        console.log(this.name)
    }
}
b.prototype.say = function () {
    return 'say'
};
var cat = new b('123456');
cat.user = '鉛筆';
cat.showName();
console.log(cat.hasOwnProperty('showName'));  //true      showName方法是構造函數b內的方法,cat對象是經過實例化b獲得的。在實例化b的時候會有這麼一步 b.call(cat,'123456'); 因此返回true
console.log(cat.hasOwnProperty('say'));       //false     say屬於cat內置原型對象(__propo__)指向原型鏈的方法,不算自身的方法,
console.log(cat.hasOwnProperty('user'));     //true   雖然屬性是在new 後加的,可是也算是對象的屬性呀,因此返回的ture

那麼若是對象中包含haoOwnProperty怎麼辦。-終極方案

function a(name) {
    this.name = name;
    this.showName = function () {
        console.log(this.name)
    }
}
function b(name) {
    this.name = name;
    this.showName = function () {
        console.log(this.name)
    }
}
b.prototype.say = function () {
    return 'say'
};
var cat = new b('123456');
cat.hasOwnProperty = function () {
    return true
};
cat.user = '鉛筆';
cat.showName();
console.log(cat.hasOwnProperty('啦啦啦')) // true
console.log(({}).hasOwnProperty.call(cat, ('啦啦啦')));  // false   此刻只能採用終極方案,
相關文章
相關標籤/搜索