一、構(gòu)造函數(shù)模式
// 工廠函數(shù)模式
functionPerson(name,age){
varobj={};
obj.name=name;
obj.age=age;
obj.sayHello=function(){
console.log("My name is"+this.name,"I am "+this.age+" years old");
}
returnobj;
}
varp1=Person("chengxiaohui",18);
p1.sayHello();
================================
// 構(gòu)造函數(shù)模式
functionPerson(name,age){
this.name=name;
this.age=age;
this.sayHello=function(){
console.log("My name is"+this.name,"I am "+this.age+" years old");
}
}
// 多了一個(gè)new
varp1=newPerson("chengxiaohui",18);
p1.sayHello();
構(gòu)造函數(shù)模式和工廠函數(shù)模式的區(qū)別?
1、執(zhí)行的時(shí)候
普通函數(shù)執(zhí)行Person函數(shù)
構(gòu)造函數(shù)模式是通過new 執(zhí)行,那Person就是一個(gè)類了
函數(shù)執(zhí)行的返回值(p1)就是Person這個(gè)類的一個(gè)實(shí)例
2、在函數(shù)代碼執(zhí)行的時(shí)候
相同點(diǎn):
都是形成一個(gè)私有作用域,然后形參賦值->預(yù)解析(變量提升)->代碼從上向下執(zhí)行
不同點(diǎn):
在代碼執(zhí)行之前,不用自己手動(dòng)創(chuàng)建對(duì)象,瀏覽器會(huì)默認(rèn)創(chuàng)建一個(gè)對(duì)象數(shù)據(jù)類型的值(這個(gè)對(duì)象其實(shí)就是當(dāng)前類的一個(gè)實(shí)例)
this代表的就是當(dāng)前的實(shí)例,然后把屬性名和屬性值賦值給當(dāng)前的實(shí)例
最后瀏覽器會(huì)默認(rèn)把創(chuàng)建的這個(gè)對(duì)象返回
// 創(chuàng)建一個(gè)數(shù)組
var ary=[ ];//字面量方式創(chuàng)建
var ary2=new Array();//構(gòu)造函數(shù)創(chuàng)建
// 無論通過哪種方式去創(chuàng)建,ary和ary2都是Array這個(gè)類的實(shí)例
1、JS中所有的類都是函數(shù)數(shù)據(jù)類型,他通過new執(zhí)行變成一個(gè)類,但是本質(zhì)上他也是一個(gè)普通函數(shù)。
2、在構(gòu)造函數(shù)模式中,類中(函數(shù)體)出現(xiàn)的this.xxx=xxx中的this是當(dāng)前類的一個(gè)實(shí)例
3、p1和p2都是Person這個(gè)類的實(shí)例,所以都擁有sayHello這個(gè)方法,但是不同實(shí)例之間的方法是不一樣的,實(shí)例和實(shí)例之間是單獨(dú)的個(gè)體,所有的私有屬性不是同一個(gè)。
console.log(p1.sayHello===p2.sayHello);//false
構(gòu)造函數(shù)里面代碼執(zhí)行的時(shí)候的不同點(diǎn)
// 構(gòu)造函數(shù)模式
function Person(name, age) {
? //在構(gòu)造函數(shù)里,瀏覽器會(huì)默認(rèn)給你創(chuàng)建一個(gè)對(duì)象
? //var obj = {};
? obj.name = name;
? obj.age = age;
? obj.sayHello = function () {
? ? console.log("My name is" + this.name, "I am " + this.age + " years old");
? }
? //瀏覽器默認(rèn)返回了
? //return obj;
}
// 多了一個(gè)new
var p1 = new Person("chengxiaohui", 18);
var p2 = new Person("zhanghuan", 19);
p1.sayHello();
構(gòu)造函數(shù)執(zhí)行的時(shí)候不傳參數(shù)可以省略()
function Fn() {
}
//沒有寫調(diào)用的小括號(hào),但是依然會(huì)執(zhí)行這個(gè)函數(shù)
var f1 = new Fn;
//作為普通函數(shù)執(zhí)行必須要加小括號(hào)
Fn();
this的問題:在類中的出現(xiàn)的this.xxx=xxx中的this都是當(dāng)前類的實(shí)例,而某一個(gè)屬性值(方法),方法中的this需要看方法執(zhí)行的時(shí)候,前面是否有點(diǎn),才能知道this指向誰
function Fn(name, age) {
? // 這個(gè)this指的是f1
? this.name = name;
? this.age = age;
? this.sayHello = function () {
? ? //這里的this要看這個(gè)函數(shù)執(zhí)行的時(shí)候才知道
? ? console.log(this)
? }
}
var f1 = new Fn("chengxiaohui", 18);
f1.sayHello();//this 指的是f1
var f2=f1.sayHello;
f2();//this指的是window
類有普通函數(shù)的一面,當(dāng)函數(shù)執(zhí)行的時(shí)候,var num其實(shí)只是當(dāng)前形成的私有作用域中的私有變量而已,他和我們的f1這個(gè)實(shí)例沒有任何的關(guān)系
function Fn(name, age) {
? //創(chuàng)建的變量
? var num;
? this.name = name;
? this.age = age;
? this.sayHello = function () {
? ? console.log(this)
? }
}
var f1 = new Fn("chengxiaohui", 18);
f1.sayHello();
var f2=f1.sayHello;
f2();
構(gòu)造函數(shù)返回值的情況
默認(rèn)類中給返回了一個(gè)對(duì)象
如果寫了return,return的是基本數(shù)據(jù)類型的話,還是返回那個(gè)默認(rèn)對(duì)象
如果寫了return,return的是引用數(shù)據(jù)類型,返回的就是return的那個(gè)東西
instanceof
檢測某一個(gè)實(shí)例是都屬于這個(gè)類(引伸用途:檢測數(shù)據(jù)類型)語法:實(shí)例 instanceof 類
console.log(f1instanceofFn);
console.log(f1instanceofObject)
f1和f2都是Fn這個(gè)類的一個(gè)實(shí)例,都擁有name和sayHello兩個(gè)屬性,但是這兩個(gè)屬性是各自的私有屬性
functionFn(name){
this.name=name;
this.sayHello=function(){
console.log(this)
}
}
varf1=newFn("chengxiaohui");
varf2=newFn("zhanghuan");
二、原型
構(gòu)造函數(shù)模式中擁有了類和實(shí)例的概念,并且實(shí)例和實(shí)例之間是相互獨(dú)立的-->實(shí)例識(shí)別如何將一個(gè)私有屬性提升為公有屬性呢?
functionFn(name){
this.name=name;
}
//放在原型上成了公有屬性
Fn.prototype.sayHello=function(){
console.log("I can say hello~");
}
varf1=newFn("chengxiaohui");
varf2=newFn("zhanghuan");
需要焊死在腦子里的三句話
1、每一個(gè)函數(shù)數(shù)據(jù)類型都有一個(gè)天生自帶的屬性:prototype(原型),這個(gè)屬性值是一個(gè)對(duì)象數(shù)據(jù)類型
2、在prototype上瀏覽器天生給他加了一個(gè)constructor屬性,屬性值是當(dāng)前函數(shù)(類)本身
3、每一個(gè)對(duì)象也天生自帶一個(gè)屬性:__proto__,屬性值是當(dāng)前實(shí)例所屬類的原型
所有的函數(shù):普通函數(shù)、類(內(nèi)置類,自定義類)都是Function的實(shí)例,F(xiàn)unction 和Object 都是Function的實(shí)例
所有的函數(shù)身上都有一個(gè)prototype 和__proto__
畫圖解析

Object是JS中所有對(duì)象數(shù)據(jù)類型的基類(最頂層的類)
f1 instanceof Object->true因?yàn)閒1通過__proto__可以向上查找,不管有多少級(jí),最終都會(huì)找到Object上
三、原型鏈查找機(jī)制
f1.hasOwnProperty("x")
1、通過對(duì)象.屬性名的方式獲取到屬性值的時(shí)候,首先在對(duì)象的私有屬性上進(jìn)行查找,如果私有屬性上有,就是私有的這個(gè)
2、如果私有屬性沒有,則通過__proto__找到所屬類的原型(類的原型上定義的屬性和方法都是當(dāng)前實(shí)例的公有屬性和方法)
3、如果原型上也沒有,則繼續(xù)通過原型的__proto__繼續(xù)向上查找,一直到Object.prototype為止
這種查找機(jī)制我們就叫做原型鏈模式!
四、習(xí)題
function Fn(){
? ? this.x=100;
? ? this.y=200;
? ? this.getX=function(){
? ? ? ? console.log(this.x);
? ? }
}
Fn.prototype.getX=function(){
? ? console.log(this.x);
}
Fn.prototype.getY=function(){
? ? console.log(this.y);
}
var f1=new Fn;
var f2=new Fn;
console.log(f1.getX==f2.getX);
console.log(f1.getY==f2.getY);
console.log(f1.__proto__.getY==Fn.prototype.getY);
console.log(f1.__proto__.getX==f2.getX);
console.log(f1.getX===Fn.prototype.getX);
console.log(f1.constructor);
console.log(Fn.prototype.__proto__.constructor);
f1.getX();
f1.__proto__.getX();
f2.getY();
Fn.prototype.getY();
============================
function fun(){
? ? this.a=0;
? ? this.b=function(){
? ? ? ? alert(this.a);
? ? }
}
fun.prototype={
? ? b:function(){
? ? ? ? this.a=20;
? ? ? ? alert(this.a);
? ? },
? ? c:function(){
? ? ? ? this.a=30;
? ? ? ? alert(this.a)
? ? }
};
var my_fun=new fun();
my_fun.b();