原型
原型是function對(duì)象的一個(gè)屬性倦淀,它定義了構(gòu)造函數(shù)制造出的對(duì)象的祖先暂衡。通過(guò)該構(gòu)造函數(shù)構(gòu)造出來(lái)的對(duì)象朵耕,可以繼承該原型的屬性和方法似袁。原型也是對(duì)象
原型知識(shí)講解
舉一個(gè)小栗子
Person.prototype.lastName="deng";
function Person(name,sex){
this.name=name;
this.sex=sex;
}
var person = new Person("xiaoliu",'male');
prototype的講解
通過(guò)上面的代碼我們不難看出,對(duì)象可以訪問(wèn)到訪問(wèn)自己的屬性
然而令人感到好奇的是叉存,通過(guò)person這個(gè)對(duì)象可以訪問(wèn)到Person.prototype上的屬性——其實(shí)這是因?yàn)镻erson.prototype是person對(duì)象的原型(就好像是祖先一樣码俩,子孫可以繼承祖先的屬性和方法),這就是person對(duì)象有l(wèi)astName屬性的原因歼捏。
增刪改查講解
-
增
原型
無(wú)論是原型還是實(shí)例對(duì)象都使用統(tǒng)一的方式增加屬性或者方法
- 刪
Person.prototype.lastName="deng";
function Person(name,sex){
this.name=name;
this.sex=sex;
}
var person = new Person("xiaoliu",'male');
毫無(wú)疑問(wèn)稿存,實(shí)例對(duì)象可以刪除自己的屬性
實(shí)例對(duì)象刪除原型上的屬性返回true,但是沒(méi)有刪除成功瞳秽,這是為什么呢瓣履?看下面演示
刪除對(duì)象上沒(méi)有的屬性都會(huì)返回ture
結(jié)論
實(shí)例對(duì)象可以刪除自己的屬性,原型可以刪除自己的屬性寂诱,實(shí)例對(duì)象不能刪除原型上的屬性拂苹。至于原型是否可以刪除實(shí)例對(duì)象的屬性——原型上是沒(méi)有實(shí)例對(duì)象的屬性的
- 查
兩種方法
方法一
- 改
第一種情況
成功修改原型上的屬性以及實(shí)例對(duì)象的屬性
由實(shí)例對(duì)象修改原型中的屬性時(shí)安聘,只能成功修改實(shí)例對(duì)象上的屬性痰洒,原型中的屬性并沒(méi)有被修改
第二種情況
結(jié)果同上一個(gè)情況一樣
這是你會(huì)發(fā)現(xiàn)此次修改也只是修改原型上的屬性瓢棒,實(shí)例對(duì)象上的屬性并沒(méi)有被修改成功,這是為什么呢丘喻?脯宿?——這是因?yàn)閷?shí)例對(duì)象已經(jīng)擁有自己的顯式屬性,所以修改原型上的屬性并不會(huì)影響實(shí)例對(duì)象的屬性
由于講解需要泉粉,先把__proto __講了
proto用于查看原型的一個(gè)屬性连霉,而且是隱式屬性
栗子栗子
Person.prototype.name = 'Sunny';
function Person() {}
var person = new Person();
淺紫色表示隱式屬性,深紫色表示顯式屬性
無(wú)論是實(shí)例對(duì)象上的proto還是原型上的proto屬性最終的原型都是Object嗡靡,Object的原型是null跺撼,person.proto==Person.prototype
修改原型上屬性的兩種方式以及它們的不同之處
- 第一種
Person.prototype.name = 'Sunny';
function Person() {}
Person.prototype.name="Cherry";
var person = new Person();
Person.prototype.name = 'Sunny';
function Person() {}
var person = new Person();
Person.prototype.name="Cherry";
顯而易見(jiàn),上面這兩個(gè)栗子只是原型修改一個(gè)屬性
- 第二種 稍微變換一下
Person.prototype.name='sunny';
function Person() {
/*內(nèi)部是這樣子的*/
//var this={
//__proto__:Person.prototype
//}
var person = new Person();
Person.prototype={
name:'cherry'
}
這個(gè)栗子先創(chuàng)建了一個(gè)實(shí)例對(duì)象讨彼,然后通過(guò)不同的方式修改Person.prototype中的name屬性歉井,猜一猜Person.prototype.name和person.name的值是什么?
實(shí)例對(duì)象和原型(也是一個(gè)對(duì)象)哈误,它們擁有對(duì)象的特點(diǎn)——存儲(chǔ)的是數(shù)據(jù)的引用哩至,當(dāng)兩個(gè)對(duì)象是同一個(gè)引用時(shí),修改一個(gè)對(duì)象的引用值時(shí)蜜自,不會(huì)影響另外一個(gè)對(duì)象的值∑忻玻現(xiàn)在person.proto和Person.prototype指向同一個(gè)空間,然后Person.prototype換一個(gè)空間重荠,而原來(lái)的person.proto沒(méi)有變箭阶,所以person.name還是為sunny,再舉一個(gè)更簡(jiǎn)單的栗子吧~
var obj = {
name: 'a'
};
var obj1 = obj;
obj = {
name: 'b'
}
現(xiàn)在應(yīng)該懂了修改引用中的值的妙處了吧~
考一考你
Person.prototype.name = 'Sunny';
function Person() {
/*內(nèi)部是這樣子的*/
//var this={
//__proto__:Person.prototype
//}}
Person.prototype = {
name: 'cherry'
}
var person = new Person();
想想預(yù)編譯過(guò)程以及函數(shù)的執(zhí)行順序(什么時(shí)候才調(diào)用構(gòu)造函數(shù))就很容易得出結(jié)果了~
constructor講解
construcor可以查看一個(gè)對(duì)象的構(gòu)造函數(shù)戈鲁,構(gòu)造器是一個(gè)隱式屬性
一個(gè)栗子引入
Person.prototype.name='sunny';
function Person() { }
var person = new Person();
而且constructor可以被修改
function Car(){}
Person.prototype.name='sunny';
function Person() {
//var this ={
//constructor:Person
//}
}
var person = new Person();
person.constructor=Car;
原型鏈
//Grand.prototype.__proto__->Object.prototype
//Object.prototype.__proto__->null
Grand.prototype.lastName = "deng";
function Grand() {}
var grand = new Grand();
Father.prototype=grand;
function Father() {}
var father = new Father();
Son.prototype=father;
function Son() {}
var son = new Son();
son實(shí)例對(duì)象查找lastname屬性時(shí)會(huì)根據(jù)原型鏈一層層往上找,直到找到為止尾膊,或者找不到返回undefined
原型鏈上的增刪改查
原型鏈上的增刪改查和原型的增刪改查是差不多的
- 這里講一個(gè)修改的小特例
在father身上加一個(gè)引用值
function Father() {
this.fortune={
fo1:"visa"
}
}
var father = new Father();
Son.prototype=father;
function Son() {}
var son = new Son();
這時(shí)通過(guò)son修改fortune
上面兩種方式不同,第一種son直接修改person.fortune荞彼,很顯然冈敛,只修改了son.fortune的值,而第二種方式是直接操作fortune引用值鸣皂,顯然是引用值增加一個(gè)屬性抓谴,只是引用值的修改。
補(bǔ)充一個(gè)知識(shí)
var obj = {}
var obj1=new Object();
//obj1._proto_ -->Object.prototype
第一種var obj = {}是對(duì)象自變量的創(chuàng)建形式寞缝,上面的兩種創(chuàng)建方式是一樣的癌压,用var obj={}的方式系統(tǒng)會(huì)默認(rèn)用new Object()的方式創(chuàng)建,平時(shí)再構(gòu)造對(duì)象時(shí)建議用對(duì)象自變量的創(chuàng)建方式荆陆,即var obj={}
new的作用
1滩届、創(chuàng)建一個(gè)新的對(duì)象
2、將構(gòu)造函數(shù)的this指向這個(gè)新對(duì)象
3被啼、返回這個(gè)新對(duì)象
Object.create()
創(chuàng)建對(duì)象的方法
var obj = Object.create(原型)
var obj= {name:"sunny",age:123};
var obj1=Object.create(obj);
obj1的原型就是obj帜消,所以obj1繼承obj的屬性
再舉一個(gè)例子
Person.prototype.name="sunny";
function Person(){
}
var person=Object.create(Person.prototype);
和
Person.prototype.name="sunny";
function Person(){
}
var person=new Person();
的結(jié)果是一樣的棠枉,但是在person的構(gòu)造函數(shù)中定義自己的屬性就不一樣了
一個(gè)錯(cuò)誤的概念
全部對(duì)象最終都會(huì)繼承自O(shè)bject.prototype
對(duì)象的原型只能是一個(gè)Object或者是null,所以我構(gòu)造一個(gè)沒(méi)有原型的對(duì)象泡挺,如下
結(jié)論
絕大多數(shù)對(duì)象最終都會(huì)繼承自O(shè)bject.prototype辈讶,有的對(duì)象沒(méi)有原型
再補(bǔ)充一下
null和undefiend不能調(diào)用toString()
因?yàn)樗鼈儧](méi)有原型
call/apply
改變this指向
call
function test(){}
test() //其實(shí)執(zhí)行會(huì)默認(rèn)為test.call()
test()和test.call()沒(méi)有區(qū)別
function Person(name,age){
//this=obj
this.name=name;
this.age=age
}
//沒(méi)有new,this指向window
var person = new Person('deng',100);
var obj={}
Person.call(obj,'cheng',200);//第二,三...是參數(shù)
call()就是改變this的指向的娄猫,上面的栗子就是讓obj使用Person的方法構(gòu)造對(duì)象贱除,這時(shí)person構(gòu)造函數(shù)的this為obj,相當(dāng)于obj.name=name,obj.age=age;
傳參
需要把實(shí)參按照形參的個(gè)數(shù)傳進(jìn)去
用法
當(dāng)兩個(gè)對(duì)象含有相同的屬性時(shí)媳溺,但是另一個(gè)對(duì)象的屬性比較多(功能涵蓋)
function Person(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
}
function Student(name,age,sex,tel,grade){
this.name=name;
this.age=age;
this.sex=sex;
this.tel=tel;
this.grade=grade;
}
var student= new Student('Sunny',123,'male',139,2019);
上面構(gòu)造對(duì)象的方式顯得累贅月幌,我們可以用call的方式使用另一個(gè)對(duì)象的構(gòu)造方法
function Person(name,age,sex){
this.name=name;
this.age=age;
this.sex=sex;
}
function Student(name,age,sex,tel,grade){
Person.call(this,name,age,sex);
this.tel=tel;
this.grade=grade;
}
var student= new Student('Sunny',123,'male',139,2019);
結(jié)論
對(duì)象名.call(對(duì)象名,參數(shù)...)可以實(shí)現(xiàn)借用別的對(duì)象的屬性來(lái)構(gòu)造本對(duì)象的屬性
apply
使用方式:對(duì)象名.(this,[參數(shù)])
區(qū)別
傳參列表不同悬蔽,call需要把實(shí)參按照形參的個(gè)數(shù)傳進(jìn)去飞醉,apply需要傳一個(gè)arguments
最后看一張圖來(lái)縷一縷自己的思路吧
function Add() {}
var add=new Add();