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