javascript里邊,沒有類的概念,可以直接創建一個對象(或通過函數)出來,對象可以有默認成員,后期也可以給對象豐富成員出來。 在js中,所有的內容的對象,一切皆是對象。 Js本身就是多態的,弱類型的
對象,屬性的無序集合。 {}的方式來表示對象。
{屬性名: 值, 屬性名:值,} 除了屬性名和屬性值之外,還有一個屬性特征
屬性的特征 主要包括可修改、可枚舉、可刪除三個。 Object.definePRoperty(cat,”gender”,{ value : “female”, //默認值為undefined writable : false, //writable表示是否能使用賦值運算符修改其值,默認為true enumerable : true, //enumerable表示是否可用枚舉該屬性,通常是指for…in,默認true configurable : false //configurable表示屬性能否被刪除,默認是true,并且不能將該值修改回去 });
使用{}定義對象的時候,writable、enumerable和configurable 都為true,也就是可以修改、可以枚舉,可以刪除。 如果使用defineProperty這個方法來創建對象屬性的話,則可以控制器這些值。
<script>var obj={'name':'小環'}//給obj定義一個屬性ageObject.defineProperty(obj,'age',{ value:5, writable:false, //意味不能重新賦值 enumerable:false, //意味不能使用for...in來枚舉 configurable:false //意味不能刪除他});console.log(obj);obj.age=50; //不能修改console.log(obj);for(var p in obj) { console.log(p,obj[p]); //不能枚舉age}delete(obj.age); //不能刪除console.log(obj);</script>注意:通常情況下,我們自定義對象的時候,是不用這么來操作的。但是js底層是這么干的。
① 字面量方式創建,字面量方式定義對象,有一個專用名稱—–json var obj = {成員名稱:值,名稱:值,名稱:值…}; ② 構造函數創建對象 var obj = new 函數名稱(); ③ Object方式創建對象 var obj = new Object();
<script>//1.字面量方式創建//var obj={成員名稱:值,成員名稱:值}var cat={name:'kitty','color':'yellow',climb:function(){ console.log('在爬樹!')} } console.log(cat.name); //kitty console.log(cat['color']); //yellow cat.climb(); //在爬樹!//可以創建一個空的,后期豐富成員var pig={}pig.color='black';pig['addr']='養殖場';pig.hobby=function(){ console.log('love eat!');}console.log(pig);//Objectaddr: "養殖場"color: "black"hobby: //()__proto__: Object//2.構造函數方式創建 var obj=new 函數名稱();function Animal(n){ //通過this聲明的成員會變成對象的默認成員 var age=5; this.weight=130; this.color-n; this.act=function(){ console.log('跑步!'); }}var dog=new Animal('gray');dog.leg=4;dog['hobby']=function(){ console.log('看家');}console.log(dog);//object方式創建var wolf=new Object();wolf.eye='閃閃發光';console.log(wolf);</script>{} 雙括號表示對象 [] 中括號表示數組 “” 雙引號內是屬性或值 冒號表示后者是前者的值(這個值可以是字符串、數字、也可以是另一個數組或對象) 所以 {“name”: “Michael”} 可以理解為是一個包含name為Michael的對象 而[{“name”: “Michael”},{“name”: “Jerry”}]就表示包含兩個對象的數組
new到底干了什么? //實際上干了如下幾件事情, 1.首先創建一個空對象 2.將this指針指向該對象 3.執行構造器中的代碼,為該對象添加屬性 4.設置該對象的constructor屬性 5.返回該對象,如果顯式返回this,效果相同,如果返回其它的值,則new的時候會返回該值。
與對象有關系的內存空間: ①. 棧空間 存放的數據大小比較小,一般大小固定的信息適合存放在該空間,例如 整型、boolean、對象的名稱(引用)。
②. 堆空間 該空間存儲的數據比較多,空間較大,一般數據長度不固定的信息在該空間存放,例如: string、Array、對象實體
③. 數據空間 該空間存放常量、類的靜態屬性
④. 代碼空間 存放函數體代碼、方法體代碼
區別: 沒有區別,就看使用,new就是構造函數,函數()就是普通函數調用。
① 普通函數調用(包括匿名函數自調用)
② 構造函數執行 new 函數
③ 作為對象的成員方法執行
④ 通過call或apply執行 函數/方法.call(函數內部this指引,實參,實參,實參。。。) 函數/方法.apply(函數內部this指引,[實參,實參,實參。。。]) call和apply使得函數執行的時候可以控制變量污染的風險。 (對象調用其他函數/方法的時候,無需為對象創建新成員)
那么下面介紹下call
<script>function f1(){ console.log('this is Thurday');}f1.call();var cat={mingzi:'波斯貓',climb:function(){ console.log(this.mingzi+'在爬樹'); }}var tiger={mingzi:'東北虎',act:function(){ console.log('猛虎撲食'); }}cat.climb.call(tiger); //東北虎在爬樹</script>構造器:使用什么元素實例化的對象,元素就稱為該對象的構造器 var cat = new Animal(); Animal就稱為cat對象的構造器。
對象.constructor; //獲得構造器
<script>function Animal(){this.age=5;}var dog=new Animal();//獲得dog的構造器console.log(dog.constructor);var f1=new Function("name","age", "console.log(name+'---'+age)");f1('tom',24); //tom---24</script>在Javascript里邊,封裝只體現public、private 構造函數內部聲明的局部變量就是私有成員
對象封裝,Js中,其實就是使用閉包。
<script>function counter(){ var cnt=0; //私有屬性 function getCnt(){return cnt;} function setCnt(val){return val;} return {getCnt:getCnt,setCnt:setCnt}}var f=counter();console.log(f.getCnt()); //0f.setCnt(100);console.log(f.getCnt()); //0</script>這個代碼的延伸—-模塊模式
在實際的代碼中,如何來操作這個原型呢? 此時,就應該使用prototype,但是請注意,它是構造器的(函數),不是對象的。
isPrototypeOf:用來判斷是否是另一個對象的原型
<script>//在某些瀏覽器可以使用console.log(p1.__proto__.isPrototypeof(p1));//在代碼中測試console.log(Person.isPrototypeof(p1));</script>javascript里邊:(構造)函數可以繼承另外一個對象,構造函數實例化出來的對象除了擁有本身成員還擁有被繼承對象的成員。
原型繼承關鍵字:prototype。 函數.prototype.成員名稱 = 值; //繼承單一成員 函數.prototype = 對象; //繼承一個對象 要在實例化對象前面繼承
<script>var cat={mingzi:'kitty',climb:function(){ console.log('在爬樹!'); }}function Tiger(){ this.color="yellow"; this.leg=4; this.act=function(){ console.log('猛虎撲食!'); }}//函數繼承對象(在實例化對象前面繼承)Tiger.prototype=cat;//繼承單一成員,后期實例化對象都有該成員Tiger.prototype.eat=function(){ console.log('吃一個動物!');}Tiger.prototype.age=5;var north=new Tiger();console.log(north);</script>① 對象 和 單一成員同時繼承,需要先繼承對象、再繼承成員 ② 多個對象 同時繼承,最后對象起作用 ③ 繼承成員名稱 與 本身成員名稱一致,體現本身成員結果
多個對象同時繼承,后者覆蓋前者
<script>function Tiger(){ this.color="yellow"; this.leg=4;}var dog={hobby:'看家'};var pig={color:'black'};Tiger.prototype=dog;Tiger.prototype=pig;Tiger.prototype.addr='東北森林'; //先繼承對象再繼承成員var north=new Tiger();console.log(north); //體現本身和pig成員</script>對象訪問成員類型一共四種,如下圖,從上往下優先級依次提高:
<script>//對象訪問成員類型和優先級function Cat(){ this.weapon = "伶牙俐齒"; //④繼承對象構造函數成員}var kitty = new Cat();kitty.weapon = "走直線"; //③ 繼承對象本身成員function Tiger(){ this.color = "yellow"; this.leg = 4; this.act = function(){ console.log('猛虎撲食'); } this.weapon = "嘶吼"; //② 構造函數成員}Tiger.prototype = kitty; //繼承對象var north = new Tiger();north.weapon = "大爪子"; //① 對象本身成員console.log(north.weapon); //大爪子</script>什么是原型鏈 構造函數 繼承 一個對象 繼承對象也有構造函數,其構造函數還去繼承其他對象 其他對象也有構造函數,構造函數還去繼承其他對象 其他對象也有構造函數,構造函數還去繼承其他對象 如此反復。。。。。 形成了一個繼承的鏈條,稱為’原型鏈’,原型鏈的頂端是Object
通過原型鏈,可以使得對象訪問到許多繼承的成員
① 對象本身獲取 ② 對象構造函數里邊獲取 ③ 構造函數繼承對象本身獲取 ④ 構造函數繼承對象的構造函數里邊獲取 構造函數繼承對象構造函數繼承對象的本身獲取 構造函數繼承對象構造函數繼承對象的構造函數里邊獲取 。。。。。。 直到找到Object成員為止。 有的時候對象訪問一個成員,我們本身并沒有定義這個成員,其就會通過原型鏈找到頂端Object的成員進行訪問。 例如constructor,hasOwnPrototype,isPrototypeOf等等都是原型鏈頂端Object的成員
for(var 成員變量 in 對象){} //遍歷對象 對象.hasOwnProperty(成員名稱) 判斷成員是否是本身的
<script>//遍歷對象 及 成員屬組判斷function Tiger(){ this.color = "yellow"; this.leg = 4; this.act = function(){ console.log('猛虎撲食'); } this.weapon = "嘶吼";}Tiger.prototype = {addr:'beijing',weight:230};//繼承對象var south = new Tiger();//遍歷對象//for(var 成員變量 in 對象){}for(var k in south){//console.log(k+"--"+south[k]);//判斷成員是本身的 還是 繼承的//對象.hasOwnProperty(成員名稱)判斷成員是否是本身的,返回boolean if(south.hasOwnProperty(k)){ console.log("自己的:"+k); }else{ console.log('繼承的:'+k); }</script>結果如下:
原型模式缺點 所有的對象,都具備相同的屬性。包括簡單的屬性。 會導致,如果對甲對象進行修改,乙對象也隨之更改,這就有問題了。
對于屬性(簡單的屬性),采用構造器的方式 對于方法(復雜的屬性),采用原型的方式 混合模式= 構造器模式 + 原型模式
<script>//混合模式function Person(name,age){ this.name=name; this.age=age;}//原型的方式添加方法Person.prototype.say=function(){ return this.name+this.age;}//使用對象var p1=new Person('小強',7);var p2=new Person('小龍',8);console.log(p1.say()); //小強7console.log(p2.say()); //小龍8</script>特點(優勢): ① 允許同時繼承多個對象 ② 非常靈活,可以根據實際需要為每個對象復制不同的成員 (之前的原型繼承,繼承成員無論是否使用都繼承給每個對象) jquery框架里邊大量使用復制繼承
對象.hasOwnProperty(參數) //判斷對象有沒有參數的成員
<script>//復制繼承function Tiger(){ this.leg=4; this.color="yellow";}Tiger.prototype.extend=function(obj){ //獲得(遍歷)obj的每個成員,賦予給當前對象this //this代表調用的當前對象 for(var k in obj){ //復制繼承成員,復制本身沒有的成員 if(this.hasOwnProperty(k)===false){ this[k]=obj[k]; } }}var south=new Tiger();var dog={mingzi:'旺財',age:6,color:'white'};var pig={hobby:'sleep睡覺'};south.extend(dog); //south把dog成員復制一份south.extend(pig); //south把pig成員復制一份console.log(south); //本身成員,dog成員,pig成員</script>javascript體現多態: ① 在函數內部可以通過arguments關鍵字進行多態處理,傳遞個數不相同的參數,通過arguments判斷,進而有不同的處理。 ② this關鍵字可以體現多態。其可以任意代表其他對象(call和apply使用)。
參數管理器arguments 形參和實參個數不一樣的時候沒關系,實參少的話,沒有給的形參就是undefined arguments表示的是實參。可以通過arguments修改傳遞過來的實參。是一個數組
<script>function sum() { console.log(arguments); //[250, 38, 2] var s=0; arguments[0]=0; //改變這個結果也會改變 for(var i=0,len=arguments.length;i<len;++i){ s += arguments[i]; } return s;}var s1=sum(250,38,2);console.log(s1); //40</script>callee關鍵字 在函數內部使用,代表當前函數的引用(名字),使用arguments.callee(實參); 應用場景:遞歸,降低代碼耦合性
<script>function f1() { arguments.callee(); //調用本函數,外面函數名改變,里面不用變}</script>如果一個類里邊,有這樣的屬性,其值不隨便發生變化,全部對象都共用一個值,該屬性就聲明為static靜態的,其在內存中無論創建多少個對象(或者說其與具體對象無關)都只占據一份空間。
為什么使用靜態成員 ① 靜態成員歸屬到類本身,可以明顯的加快訪問速度(不需要實例化對象,通過類進行訪問)。 ② 節省內存 一個類,每實例化一個對象,在堆空間都要給每個成員分配內存空間,如果有一個成員$country無論創建多少個對象其的信息值也不發生變化,為了節省內存空間的使用,就把這樣的成員設置為“靜態成員”。其在內存中就只占據一份內存空間。
在javascript里邊如果一個成員是通過(構造)函數直接調用的,就稱其為“靜態成員”。
<script>function Animal(){ this.age=5; this.leg=4;}//給Aniaml設置成員Animal.color='black';Animal.run=function(){ console.log('奔跑');}var dog=new Animal();//其中函數對象的成員(color/run)就是'靜態成員',一個是靜態屬性,一個靜態方法//兩種對象有各自的訪問成員console.log(Animal.color); //blackAnimal.run(); //奔跑console.log(dog.age); //5console.log(dog.leg); //4//注意這2種對象成員不能交叉訪問console.log(dog.color); //underfinedconsole.log(Animal.age); //underfined</script>(function(){})() 特點代碼沒有停頓,立即發生執行,其中里面可以有形參
<script>(function() { console.log("匿名函數被調用");})();//匿名函數被調用(function(week) { console.log("今天是"+week);})("星期天");//今天是星期天</script>在js中,有兩個單體內置對象, Math Global
其中Global無法引用。真正要注意的是Math。 所謂單體內置,是指常駐內存的對象,js代碼一旦進入執行狀態,在內存中就有它們了。所以可以直接使用,根本不需要實例化的過程。
Math是一個數學對象,用于計算的。
常用的一些方法: Ceil():向上取整 Floor():向下取整 Round():四舍五入 Random():隨機,0~1之間的小數。
Global是全局對象,在js中,本身是無法看到(訪問)的。 但是如果是在瀏覽器中使用的話,window就充當了global的角色,它表示全局對象。在nodejs中就可以訪問global。
所有全局的內容都是global對象的屬性。
所以,我們用的alert函數,setTimeout函數,定義的全局變量,都可以使用window來引用。
首先看一個問題: 為什么,普通的字符串可以直接調用字符串函數。 為什么,個普通的字符串,添加屬性是無效的。
<script>var s="javascript";console.log(typeof s); //stringconsole.log(s); //javascriptconsole.log(s.length); //10s.name='js';console.log(s.name); //underfined (思考為什么?)</script>在js中,有一個包裝對象的概念。 對于基本數據類型(數值、字符串、布爾),可以直接調用相應的方法。原因在于在真正調用方法的那一刻,對當前數據做了一個包裝。
相當于執行了如下代碼:
<script>var s="javascript";//在調用開始的那一刻,使用new得到一個新的對象s1=new String(s);//中間是對s1的操作//..............//調用完畢的那一刻,將這個對象銷毀s1=null;</script>注意兩點: 它是一瞬間執行的 在整個過程中,我們是無法干涉的。
包裝的過程,有時候稱為 裝箱 和 拆箱
在js中,基本數據類型都會有對應的包裝類型.實際上也就三個: 字符串 String 數值 Number 布爾 Boolean
|
新聞熱點
疑難解答