js---聖盃模式 ,列舉,如何區分陣列和物件,callee
阿新 • • 發佈:2018-11-12
1. 繼承發展史(從a發展到d)
a 原型鏈繼承:過多的繼承沒有用的屬性
function Grand(){this.grand='grand';this.name='haha'} function Father(){this.father='father'} function Son(){this.son='son'} var grand = new Grand(); Father.prototype=grand; var father = new Father(); Son.prototype=father; var son = new Son(); console.log(son.son,son.father,son.grand);//son father garnd 可以看出來形成了原型鏈,但是我可能不想要grand身上的name卻也繼承了
b 借用建構函式---不能借用建構函式的原型,每次都要多呼叫一次函式。降低效率
function Father(){
this.address=123;this.familyCount=3;
}
function Son(){
Father.call(this); //---> this.address=123;this.familyCount=3;//重複
this.name='xiaoming'
}
c 公有原型---明顯的缺陷:修改子,會影響父
function Father(){ this.familyCount=3; } Father.prototype.address=123; function Son(){ this.name = 'xiaoming'; } Son.prototype = Father.prototype;//現在Father和Son的原型都是Father.prototype那個房間裡的東西,一動都變 var father = new Father(); var son = new Son(); console.log(son.address,father.address);//123 123 Son.prototype.address = 234; console.log(son.address,father.address);//234 234 如果子搬出去住了,想改屬性的值,或者給自己加了一個屬性,父的也會變!!
d 聖盃模式---利用中間函式構造出的物件作為中間過度原型,產生原型鏈
function Father(){
this.familyCount=3;
}
function Son(){
this.name = 'xiaoming';
}
Father.prototype.address='haha';
//封裝一個繼承函式 閉包的形式可以使F隱起來,不被訪問到---閉包的私有化變數的使用方法
var inherit = (function(){
var F=function(){};
return function(target,source){
F.prototype = source.prototype; //將source的原型和F的原型變成同一個
target.prototype = new F(); //建立一個__proto__指向source.prototype的{},並讓target構造出的物件都繼承自這個{}
//此時,修改target.prototype相當於是在這個空的{}中做修改,不會有任何影響
target.prototype.constuctor = target; //修改原型會導致原型失去自己建構函式的指向
target.prototype.uber = source.prototype; //超類:記錄真正繼承的的原型
};
})();
inherit(Son,Father);
var son=new Son();
console.log(son.address);//haha
2. 列舉---就是遍歷
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.secret='每個人都不一樣';
var obj = new Person('xiaozhang',24);
for(var key in obj){
//過濾不是當前物件自己的屬性
if(obj.hasOwnProperty(key)){
console.log(key+'是當前物件自己的','值是:'+obj[key]);//必須用obj[key],不能用obj.key
//因為用.取屬性會讓系統自動轉換為obj['key'],就是說系統預設點後就是字串形式
}else{
//為false----會打印出原型鏈上所有人為設定的屬性,系統自帶的不會打印出來!!
console.log(key+'是繼承來的');
}
}
'name' in obj;//true
'secret' in obj;//true in不論是當前物件裡的還是原型鏈上的人為設定的屬性都是返回true
3. A instanceof B----A物件的原型鏈上 有沒有 B的原型 A物件是不是可以繼承B的原型 A物件 是不是 由B函式構造出來的
例子---區分陣列和物件:
var arr=[1,2],obj={};
//法一: 由誰構造的---可能會不靠譜
console.log(arr.constructor,obj.constructor); //function Array(){} function Object(){}
//法二: instanceof 原理差不多,原型鏈上有沒有Array ---可能不靠譜
console.log(arr instanceof Array,obj instanceof Array); //true false
//法三: 呼叫Object的toString方法 建議使用這種方式,其他兩種方式在父子域的情況下會出錯,就iframe引入一個子頁面,在子頁面[] instanceof Array結果是false,因為這裡的Array等於取了父域中的Array,跨域
console.log(Object.prototype.toString.call(arr),Object.prototype.toString.call(obj)); //[Object Array] [Object Object]
4. callee---屬於arguments 的一個函式,就是自己
例子---立即執行函式沒有名字,但是要寫遞迴的時候:
var num=(function(n){ //沒函式名
if(n==1){return 1}
return n*arguments.callee(n-1);//這裡回撥自己
}(5));
console.log(num);//120
5. 寫個小栗子---this
var foo = 123;
function print(){
this.foo = 234;
console.log(foo);
}
new print();//this是{}---> this.foo=234---> {foo:234}---> 列印的是foo,不是this.foo---> foo是個變數,請在作用域鏈上找,只有全域性有個foo是123
print(); //this是window ---> window.foo = 234 ---> 所以foo從123變成了234