1. 程式人生 > >js---聖盃模式 ,列舉,如何區分陣列和物件,callee

js---聖盃模式 ,列舉,如何區分陣列和物件,callee

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