對象的遍歷 對象可以當做數組處理,使用for in var person={}; person.name="cyy"; person.age=25; person.infos=function(){ alert(this.name+" "+this.age); } for(var i in pers ...
對象的遍歷
對象可以當做數組處理,使用for in
var person={}; person.name="cyy"; person.age=25; person.infos=function(){ alert(this.name+" "+this.age); } for(var i in person){ console.log(i);//屬性名或方法名 console.log(person[i]);//屬性值或方法值 }
使用構造函數聲明的對象,需要實例化之後再進行遍歷
function Person(){ this.name="cyy"; this.age=25; } var p=new Person(); for(var i in p){ console.log(i+":"+p[i]); }
對象在記憶體中的分佈
參考以下神圖
封裝:把對象的內部數據和操作細節進行隱藏
提供private關鍵詞隱藏某些屬性和方法,限制被封裝的數據或者內容的訪問,只對外提供一個對象的專門訪問的介面
介面一般為調用方法
不過js沒有提供這樣的關鍵詞,但可以通過閉包來實現
函數內部聲明的變數,外部是訪問不到的
function fn(){ var n=1; function fn2(){//特權方法 alert(++n); } return fn2; } fn()();//2
//封裝 function Person(){ var name="cyy"; function _name(){ alert(name); } this.name=function(){//這是給外部的介面 return _name; } } var p=new Person(); var fn=p.name(); fn();//cyy
封裝的缺點:1、占用記憶體 2、不利於繼承
利用閉包特性來封裝一個對象student,運用對象student存儲一個學生的信息,信息包括姓名,性別和年齡,這些信息不可被外部直接訪問,只能通過對象的方法獲取
student的數據結構如下:
//封裝 function Student(){ var obj={}; function _set(name,sex,age){ obj.name=name; obj.sex=sex; obj.age=age; } function _get(){ return obj.name+" "+obj.sex+" "+obj.age; } obj.get=function(){//對外介面 return _get; } obj.set=function(){//對外介面 return _set; } return obj; } var stu=new Student; stu.set()("小明", "男", 23); console.log(stu.get()());//小明 男 23
原型和原型鏈
原型:利用 prototype 添加屬性和方法,prototype對象
原型鏈:JS在創建對象時,有一個 __proto__ 的內置屬性,指向它的原型對象 prototype
var Person=function(){} var p=new Person(); Person.prototype.say=function(){ alert("老娘超美"); } p.say(); /* p沒有say方法,所以會去p.__proto__里找 p.__proto__是一個對象,指向Person.prototype Person.prototype中有say方法 */ /* 創建對象的過程 1、創建對象 var p={} 2、將Person的原型對象賦值給p p.__proto__=Person.prototype 3、初始化對象p Person.call(p) */ alert(p.__proto__==Person.prototype);//true
原型和原型鏈,實現原型繼承
var Person=function(){}//Person是一個對象 Person.prototype.say=function(){ alert("陳鶯鶯超美"); } var Cyy=function(){};//Cyy也是一個對象 Cyy.prototype=new Person();//將Cyy的原型指向Person,實現Cyy繼承自Person Cyy.prototype.sing=function(){ alert("陳鶯鶯會唱歌"); } var me=new Cyy(); me.say();//陳鶯鶯超美 me.sing();// 陳鶯鶯會唱歌 /* 分析:me.__proto__ -> Cyy.ptototype -> Person.prototype Person是父 Cyy是子 繼承:如果子類中沒有的,會繼承自父類;如果子類和父類中都有,那麼子類的會覆蓋掉父類的 */
__proto__ 實現原型繼承
function Person(name,age){ this.name=name; this.age=age; } Person.prototype.say=function(){ alert(this.name+" "+this.age); } function Student(){}; Student.prototype=new Person("cyy",25); //Person是Student的父類 //子類必須繼承自父類的實例 Student.prototype.grade=3; Student.prototype.test=function(){ alert(this.grade); } var s=new Student(); s.say();//cyy 25 s.test();//3 //s.__proto__ -> Student.prototype -> Person.prototype
原型的值可以是一個對象,也可以是null
原型鏈的最終指向null
alert(Object.prototype.__proto__);//null
// 情況一 function Parent(){ this.name="parent"; this.age=45; } function Child(){ this.age=25; } Child.prototype.name="child"; Child.prototype=new Parent(); var c=new Child(); console.log(c.name);//parent // 情況二 function Parent(){ this.name="parent"; this.age=45; } function Child(){ this.age=25; } Child.prototype=new Parent(); Child.prototype.name="child"; var c=new Child(); console.log(c.name);//child
情況一中,Child.prototype=new Parent(); 這一句覆蓋掉了前面的 Child.prototype.name="child";
屬性的值與代碼執行順序有關,後繼承的父級的,會覆蓋住先定義的自己的
創建一個動物類的對象 ,對象中有動物名稱和數量的屬性 。創建一個貓的對象並繼承動物類對象 ,併為貓對象定義一個方法 。實例化一個貓對象 ,調用其方法 ,彈出動物名稱和數量
function Animal(name,number){ this.name=name; this.number=number; } function Cat(){}; Cat.prototype=new Animal("cat",30); Cat.prototype.info=function(){ alert(this.name+" "+this.number); } var c=new Cat(); c.info();//cat 30
構造函數的繼承
在子類內部構造父類的對象來實現繼承
父對象被子對象繼承後,所有的屬性和方法,都會傳遞到子對象中
function Parent(name){ this.name=name; this.pSay=function(){ alert(this.name); } } function Child(name,age){ this.obj=Parent; this.obj(name);//繼承了父元素中的兩句代碼 this.age=age; this.cSay=function(){ alert(this.name+" "+this.age); } } var p=new Parent("爸爸"); p.pSay();//爸爸 var c=new Child("女兒",25); c.cSay();//女兒 25 c.pSay();//女兒
對象內置方法中的apply和call都可用於繼承,兩者的區別在於傳參方式不同
obj.call( 方法, var1, var2...)
obj.apply( 方法, [var1, var2...])
function Parent(name,age,sex){ this.name=name; this.age=age; this.sex=sex; this.say=function(){ alert(this.name+" "+this.age+" "+this.sex); } } function Child(name,age){ //實現繼承 Parent.call(this,name,age);//this是指Child } function Child2(name,age){ //實現繼承 Parent.apply(this,[name,age]);//this是指Child } var c=new Child("cyy",25); c.say(); //cyy 25 undefined //Child也擁有了Parent的屬性和方法 var c2=new Child2("cyy2",25); c2.say();//cyy2 25 undefined
使用構造方法創建一個動物類對象Animal, 對象中定義屬性有動物名稱和數量 ,並且定義一個方法。再創建兩個動物的對象(如貓和狗),一個動物使用call方法實現繼承Animal, 一個動物使用apply方法實現繼承Animal。分別實例化兩個動物並彈出動物的名稱和數量
function Animal(name,num){ this.name=name; this.num=num; this.getInfo=function(){ alert(this.name+" "+this.num); } } function Cat(name,num){ Animal.call(this,name,num); } function Dog(name,num){ Animal.apply(this,[name,num]); } var c=new Cat("cat",20); c.getInfo();//cat 20 var d=new Dog("dog",30); d.getInfo();//dog 30
JS面向對象的關鍵詞
instanceof 變數是否是對象的實例
var arr=new Array(); console.log(arr instanceof Array);//true console.log(arr instanceof Object);//true function Person(){}; var p=new Person(); console.log(p instanceof Person);//true console.log(p instanceof Object);//true
delete 刪除對象屬性(不能刪除原型鏈中的屬性和方法)
function Person(){ this.name="cyy"; this.eat=function(){ alert("吃飯"); } } var p=new Person(); console.log(p.name);//cyy delete p.name;//刪除對象的屬性 console.log(p.name);//undefined p.eat();//吃飯 delete p.eat();//吃飯 刪除對象的方法,失敗 p.eat();//吃飯 var name="cyy"; console.log(name);//cyy delete name; console.log(name);//name is not defined
call 參數逐個實現繼承
apply 參數以數組方式實現繼承
function add(a,b){ alert(a+b); } function sub(a,b){ alert(a-b); } add.call(sub,4,8); //12 調用的是add這個方法 add.call(sub2,4,8); //sub2 is not defined 只能引用一個已經存在的對象 add.apply(sub,[3,2]);
function Animal(){ this.name="animal"; this.show=function(){ alert(this.name); } } function Cat(){ this.name="cat"; } var a=new Animal(); var c=new Cat(); a.show.call(c);//cat c擁有了a所擁有的show方法 a.show.apply(c,[]);//cat c擁有了a所擁有的show方法
創建兩個數組 ,並運用apply實現兩個數組的拼接
var arr1=[2,3]; var arr2=[4,5]; arr1.push.apply(arr1,arr2); //調用的是apply前面的方法:arr1.push console.log(arr1);
arguments 實參的類數組對象
callee 返回正在執行的function對象,返回的是function的內容
arguments.callee
function fn(){ console.log(arguments.callee); /*ƒ fn(){ console.log(arguments.callee); } */ //console.log(arguments.callee());不停調用自身,陷入死迴圈 } fn();
常用於遞歸函數調用函數自身
var sum=function(n){ if(n<=1) return 1; return n+sum(n-1); } console.log(sum(4));//10
var sum=function(n){ if(n<=1) return 1; return n+arguments.callee(n-1); } console.log(sum(4));//10
this 指向當前對象
1、this函數調用
var x=1; function fn(){ this.x=2;//this改變的是全局變數的x的值 } fn(); console.log(x);//2
2、this作為方法調用
構造函數內指代當前對象
function Person(){ this.name="cyy"; this.show=function(){ alert(this.name); } } var p=new Person(); p.show();//cyy
3、在call和apply中,this作為第一個參數
var name="cyy"; function show(){ alert(this.name); } var obj={}; obj.name="cyy2"; obj.showName=show; obj.showName.apply();//調用show(),this指向全局 obj.showName.apply(window);//同上 obj.showName.apply(obj);//調用show(),this指向obj
用arguments計算參數總和
function sum(){ var sum=0; for(var i=0;i<arguments.length;i++){ sum+=arguments[i]; } return sum; } console.log(sum(2,5,7));//14
對象冒充:將父類的屬性和方法傳給子類,作為特權屬性和特權方法
function Parent(name,age){ this.name=name;//特權屬性 this.age=age; this.show=function(){//特權方法 alert(this.name+" "+this.age); } } Parent.prototype.walk=function(){//非特權方法 alert("walking..."); } function Child(name,age,sex){ this.obj=Parent;//對象冒充,可以使用父類的特權屬性和特權方法 this.obj(name,age); this.sex=sex; } var c=new Child("cyy",25,"女"); c.show();//cyy 25 c.walk();// c.walk is not a function