摘要:進(jìn)階第一章作用域深入和面向?qū)ο箢A(yù)解釋全局作用域當(dāng)瀏覽器加載頁面的時(shí)候,提供了一個(gè)全局代碼執(zhí)行的環(huán)境預(yù)解釋變量提升在當(dāng)前的作用域中,代碼執(zhí)行之前,瀏覽器首先會(huì)默認(rèn)的吧所有帶有和的進(jìn)行提前聲明或定義理解聲明和定義聲明告訴瀏覽器在全局作用域中有
JS進(jìn)階 第一章作用域深入和面向?qū)ο?/b> 預(yù)解釋
1、全局作用域:當(dāng)瀏覽器加載HTML頁面的時(shí)候,提供了一個(gè)全局js代碼執(zhí)行的環(huán)境
2、預(yù)解釋(變量提升)
在當(dāng)前的作用域中,js代碼執(zhí)行之前,瀏覽器首先會(huì)默認(rèn)的吧所有帶有var和function的進(jìn)行提前聲明或定義
1)理解聲明和定義
var num=12;聲明(declare) : var num;->告訴瀏覽器在全局作用域中有一個(gè)num的變量了
如果一個(gè)變量只是聲明但是還沒有賦值,默認(rèn)值是undefined
定義(defined):num=12->給我們的變量進(jìn)行賦值
2)對(duì)于帶var和function關(guān)鍵字的再預(yù)解釋的時(shí)候操作是不一樣的
var ->在預(yù)解釋的時(shí)候只是提前聲明不定義function->在預(yù)解釋的時(shí)候提前聲明和定義都完成了
3)預(yù)解釋只發(fā)生在當(dāng)前的作用域下,例如:開始只對(duì)window下的進(jìn)行預(yù)解釋,只有在函數(shù)執(zhí)行的時(shí)候才會(huì)對(duì)函數(shù)中的進(jìn)行預(yù)解釋
3、JS中內(nèi)存的分類
棧內(nèi)存:用來提供一個(gè)供js代碼執(zhí)行的環(huán)境->作用域
堆內(nèi)存:用來存儲(chǔ)引用數(shù)據(jù)類型的值->對(duì)象存儲(chǔ)的是屬性名和屬性值,函數(shù)存儲(chǔ)的是代碼字符串。
4、如果區(qū)分私有變量和全局變量?
1)在全局作用域下聲明(預(yù)解釋的時(shí)候)的變量是全局變量
2)在私有作用域中聲明的變量和函數(shù)的形參都是私有變量
在私有作用域中,我們代碼執(zhí)行的時(shí)候遇到了一個(gè)變量,首先我們確定它是否是私有變量,如果是私有變量,那么和外面沒有任何的關(guān)系,如果不是使用的,則往當(dāng)前作用域的上級(jí)作用域進(jìn)行查處,如果上級(jí)作用域也沒有則繼續(xù)查找,一直找到window為止...作用域鏈
6、當(dāng)函數(shù)執(zhí)行的時(shí)候(直接目的:讓函數(shù)體中的代碼執(zhí)行),首先會(huì)形成一個(gè)新的私有作用域,然后按照如下的步驟執(zhí)行:
如果有形參,先給形參賦值
進(jìn)行私有作用域的預(yù)解釋
私有作用域中的代碼從上到下的執(zhí)行
函數(shù)形成一個(gè)姓的私有的作用域保護(hù)了里面的私有變量不受外界的干擾(外面修改不了私有的,私有的也修改不了外面的),我們管這種機(jī)制叫做閉包
7、在全局作用域中,帶var和不帶var的關(guān)系
區(qū)別:帶var的可以進(jìn)行預(yù)解釋,所以在賦值的前面執(zhí)行不會(huì)報(bào)錯(cuò);不帶var的是不能進(jìn)行預(yù)解釋的,在前面執(zhí)行會(huì)報(bào)錯(cuò)
8、預(yù)解釋是毫無節(jié)操的一種機(jī)制
1)預(yù)解釋的時(shí)候不管你的條件是否成立,都要把帶var的進(jìn)行提前聲明
if(!("num") in window){ var num=12; } console.log(num);
2)預(yù)解釋的時(shí)候只預(yù)解釋“=”左邊的,右邊的是值,不參與預(yù)解釋匿名函數(shù)之函數(shù)表達(dá)式:把函數(shù)定義的部分但當(dāng)做一個(gè)值賦值給我們的變量/元素的某個(gè)事件
//window下的預(yù)解釋:var fn; fn();//Uncaught TypeError: fn is not a function var fn=function(){ console.log("ok"); }
3)執(zhí)行函數(shù)定義的那個(gè)function在全局作用域下不進(jìn)行預(yù)解釋,當(dāng)前代碼執(zhí)行到這個(gè)位置的時(shí)候定義和執(zhí)行一起完成了自執(zhí)行函數(shù):定義和執(zhí)行一起完成了
(function(){})(100);
4)函數(shù)體中return下面的代碼雖然不再執(zhí)行了,但是需要進(jìn)行預(yù)解釋;return后面跟著的都是我們返回的值,所以不進(jìn)行預(yù)解釋
function fn(){ console.log(num); retrun function(){ }; var num=100; } fn();//undefined;
5)在預(yù)解釋的時(shí)候,如果名字已經(jīng)聲明過了,不需要重新的聲明,但是需要重新的賦值;(在JS中如果變量的名字和函數(shù)的名字重復(fù)了,也算沖突了)
var fn=13; function fn(){ console.log("ok"); } console.log(fn);//13 //預(yù)解釋的時(shí)候先預(yù)解釋var fn;function fn{console.log("ok")} //然后 fn=13->給fn賦值 //最后控制臺(tái)輸出的是13
fn(); function fn(){console.log(1)}; fn(); var fn=10; fn(); function fn(){console.log(2)} fn(); //window 預(yù)解釋: /*1)聲明+定義 fn=xxxfff000; 聲明var fn(不需要重新聲明) 聲明(不重復(fù)進(jìn)行)+定義 fn=xxxfff111; 預(yù)解釋完成后此時(shí)的fn變量指向的是堆內(nèi)存地址是xxxfff111 即:存儲(chǔ)“console.log(2)”代碼字符串的堆內(nèi)存空間 2)代碼由上到下執(zhí)行 fn()//2 fn();//2 fn=10; fn();//Error:fn is not a function js代碼出錯(cuò),在沒有任何特殊處理的情況下后面的代碼不執(zhí)行 */
9、如果查找當(dāng)前作用域的上一級(jí)作用域?
看當(dāng)前函數(shù)是在那個(gè)作用域下定義的,那么他的上級(jí)作用域就是誰->和函數(shù)在哪執(zhí)行沒有任何關(guān)系
內(nèi)存釋放和作用域銷毀堆內(nèi)存釋放
對(duì)象數(shù)據(jù)類型或者函數(shù)數(shù)據(jù)類型在定義的時(shí)候首先都會(huì)開辟一個(gè)堆內(nèi)存,堆內(nèi)存有一個(gè)引用的地址,如果外面有變量等知道這個(gè)地址,我們就說這個(gè)內(nèi)存被占用了,就不能銷毀我們?nèi)绻胍褍?nèi)存釋放/銷毀,只需要把所有引用他的變量賦值為null即可,如果當(dāng)前的堆內(nèi)存沒有任何東西被占用,那么瀏覽器會(huì)在空閑的時(shí)候把他銷毀
var obj1={name:"candy"} var obj2=obj1; obj1=null; obj2=null;
棧內(nèi)存的銷毀
1)全局作用域只有當(dāng)前頁面關(guān)閉的時(shí)候全局作用域才會(huì)被銷毀
2)私有作用域(只有函數(shù)執(zhí)行才會(huì)產(chǎn)生私有作用域)
一般情況下,函數(shù)執(zhí)行會(huì)形成一個(gè)新的私有的作用域,當(dāng)私有作用域中的代碼執(zhí)行完成后,我們當(dāng)前作用域都會(huì)主動(dòng)的進(jìn)行釋放和銷毀
但是還是存在特殊情況的:
當(dāng)前私有作用域中的部分被作用域以外的東西占用了,那么當(dāng)前的這個(gè)作用域就不能銷毀了
函數(shù)執(zhí)行返回了一個(gè)引用數(shù)據(jù)類型的值,并且在函數(shù)的外面被一個(gè)其他的東西接收了,這種情況下一般形成的私有作用域都不會(huì)銷毀
在一個(gè)私有作用域中給DOM元素的事件綁定方法,一般情況下我們的使用作用域都不能銷毀
下述情況不能立即銷毀:fn返回的函數(shù)沒有被其他的東西占用,但是還需要執(zhí)行一次,所以暫時(shí)不銷毀,當(dāng)返回的值執(zhí)行完成后,瀏覽器會(huì)在空閑的時(shí)候把他銷毀
function fn(){ var num=100; return function(){ } } var f=fn();//fn執(zhí)行形成的這個(gè)私有作用域就不能被銷毀
var oDiv=document.getElementById("div1"); ~function(){ oDiv.onclick=function(){ } }()//當(dāng)前自執(zhí)行函數(shù)形成的這個(gè)使用作用域也不能銷毀
function fn(){ var num=100; return function(){ } } fn()();//首先執(zhí)行fn,返回一個(gè)小函數(shù)對(duì)應(yīng)的內(nèi)存地址,然后緊接著讓返回的小函數(shù)執(zhí)行this
我們?cè)趈s中主要研究的都是函數(shù)中的thisJS中this代碼的是當(dāng)前行為執(zhí)行的主體;JS中的context代表的是當(dāng)前行為執(zhí)行的環(huán)境(區(qū)域)
this是誰和函數(shù)在哪定義的和在哪執(zhí)行的都沒有任何的關(guān)系*
如何區(qū)分this?
單例模式函數(shù)執(zhí)行,首先看函數(shù)名前面是否有“.”,有的話 “.”前面是誰this就是誰,沒有的話就是window
自執(zhí)行函數(shù)中的this永遠(yuǎn)是window
給元素的某一個(gè)事件綁定方法,當(dāng)事件觸發(fā)的時(shí)候,執(zhí)行對(duì)應(yīng)的方法,方法中的this是當(dāng)前的元素
1、對(duì)象數(shù)據(jù)類型的作用:把描述同一個(gè)實(shí)物(同一個(gè)對(duì)象)的屬性和方法放在一個(gè)內(nèi)存空間下,起到了分組的作用,這樣不同事物之前的屬性名即使相同也不會(huì)發(fā)生沖突->我們把這種分組編寫代碼的模式叫做 單例模式
//在單例模式中我們把person1或者person2也叫做“命名空間” var person1={ name:"candy", age:28 } var person2={ name:"andy", age:30 }
2、單例模式是一種項(xiàng)目開發(fā)中經(jīng)常使用的模式,因?yàn)轫?xiàng)目中我們可以使用單例模式來進(jìn)行我們的“模塊化開發(fā)”
模塊化開發(fā) :對(duì)于一個(gè)相對(duì)來說比較大的項(xiàng)目,需要多個(gè)人協(xié)作開發(fā)的,我們一般情況下會(huì)根據(jù)當(dāng)前項(xiàng)目的需求劃分成幾個(gè)功能版塊,每個(gè)人負(fù)責(zé)一部分,同時(shí)開發(fā),最后把每個(gè)人的代碼合并
//公共模塊 var utils={ select:function(){ } } //頁卡模塊中的change->實(shí)現(xiàn)選項(xiàng)卡切換 var tabRender={ change:function(){ utils.select();//在自己的命名空間下調(diào)用其他的命名空間的方法 } } //搜索模塊change->搜索內(nèi)容變化處理 var serchRender={ change:function(){ }, clickEven:function(){ this.change();//在自己的命名空間下調(diào)用其他的命名空間的方法 } }工廠模式
1、單例模式雖然解決了分組的作用,但是不能 實(shí)現(xiàn)批量生產(chǎn),屬于手工作業(yè)模式,為了應(yīng)對(duì)這種情況就催生了“工廠模式”;
工廠模式:把實(shí)現(xiàn)同一件事情的相同代碼放到一個(gè)函數(shù)中,以后如果想再實(shí)現(xiàn)這個(gè)功能,不需要重新的編寫這些代碼了,只需要執(zhí)行當(dāng)前的函數(shù)即可;我們把這種形式又稱為 函數(shù)的封裝作用:低耦合高內(nèi)聚->減少頁面中的冗余代碼,提高代碼的重復(fù)利用率
function createJsPerson(name,age){ var obj={}; obj.name=name; obj.age=age; obj.writeJs=function(){ console.log("my name is "+this.name+",i can write js!"); } return obj; } var p1=createJsPerson("andy",30); p1.writeJS(); var p2=createJsPerson("candy",28); p2.writeJS();
JS中不存在重載
JS是一門輕量級(jí)的腳本”編程語言“(HTML+CSS不屬于編程語言,屬于標(biāo)記語言)所有的編程語言都是面向?qū)ο箝_發(fā)的->類的繼承、封裝、多態(tài)
繼承:子類繼承父類中的屬性和方法
多態(tài):當(dāng)前方法的多種形態(tài)->后臺(tái)語言中:多態(tài)包含重載和重寫
//后臺(tái)中的重載 public void sum(int num1,int num2){ } public void sum(String num1,int num2){ }
function sum(num1,num2){ } function sum(num1){ } //js中不存在重載,方法名一樣的話,后面的會(huì)把前面的覆蓋掉,最后只保留一個(gè)
JS中有一個(gè)操作類似重載的方法但是不是重載:我們可以根據(jù)傳遞參數(shù)的不一樣,實(shí)現(xiàn)不同的功能重寫:子類重寫父類的方法
function sum(num){ if(typeOf num==="undefined"){ return 0; } return num(); } sum(100); sum();構(gòu)造函數(shù)模式
//構(gòu)造函數(shù)模式的目的就是為了創(chuàng)建一個(gè)自定義類,并且創(chuàng)建這個(gè)類的實(shí)例 function CreateJsPerson(name,age){ //瀏覽器默認(rèn)創(chuàng)建的對(duì)象就是我們的實(shí)例p1->this this.name=name; this.age=age; this.writeJs=function(){ console.log("my name is "+this.name+",i can write js"); } //瀏覽器再把創(chuàng)建的實(shí)例默認(rèn)的進(jìn)行返回 } var p1=new CreateJsPerson("candy",28); p1.writeJs(); var res=CreateJsPerson("andy",30); console.log(res); /* 這樣寫不是構(gòu)造函數(shù)執(zhí)行而是普通的函數(shù)執(zhí)行 由于沒有寫return 所以 res=undefined 并且CreateJsPerson這個(gè)方法中的this是window */ var p2=new CreateJsPerson("candice",29); p2.writeJs();
1、構(gòu)造函數(shù)模式和工廠模式的區(qū)別?
1)執(zhí)行的時(shí)候
普通函數(shù)執(zhí)行->createJsPerson();
構(gòu)造函數(shù)模式->new CreateJsPerson() 通過new執(zhí)行后,我們的CreateJsPerson就是一個(gè)類了;而函數(shù)執(zhí)行的返回值(p1)就是CreateJsPerson這個(gè)類的一個(gè)實(shí)例
2)在函數(shù)代碼執(zhí)行的時(shí)候
相同點(diǎn):都是形成一個(gè)私有的作用域,然后 形參賦值->預(yù)解釋->代碼從上到下執(zhí)行(類和普通函數(shù)一樣,它也有普通函數(shù)的一面)
不同點(diǎn):在代碼執(zhí)行之前,構(gòu)造函數(shù)模式不用自己在手動(dòng)的創(chuàng)建對(duì)象了,瀏覽器會(huì)默認(rèn)的創(chuàng)建一個(gè)對(duì)象數(shù)據(jù)類型的值(這個(gè)對(duì)象其實(shí)就是我們當(dāng)前類的一個(gè)實(shí)例);接下來代碼從上到下執(zhí)行,以當(dāng)前的實(shí)例為執(zhí)行的主體(this代表的就是當(dāng)前的實(shí)例),然后分別把屬性名和屬性值賦值給當(dāng)前的實(shí)例,最后瀏覽器會(huì)默認(rèn)的把創(chuàng)建的實(shí)例返回
2、構(gòu)造函數(shù)解析
1)JS中所有的類都是函數(shù)數(shù)據(jù)類型的,它通過new執(zhí)行變成了一個(gè)類,但是它本身也是一個(gè)普通的函數(shù);JS中所有的實(shí)例都是對(duì)象數(shù)據(jù)類型
2)在構(gòu)造函數(shù)模式中,類中(函數(shù)體中)出現(xiàn)的this.xxx=xxx中的this是當(dāng)前類的一個(gè)實(shí)例
3)p1和p2都是CreateJsPerson這個(gè)類的實(shí)例,所以都擁有writeJs這個(gè)方法,但是不同實(shí)例之間的方法是不一樣的,在類中給實(shí)例增加的屬性(this.xxx=xxx)屬于當(dāng)前實(shí)例的私有屬性,實(shí)例和實(shí)例之間是多帶帶的個(gè)體,所以私有的屬性之間是不相等的
console.log(p1.writeJs===p2.writeJs);//false
3、構(gòu)造函數(shù)相關(guān)知識(shí)點(diǎn)
function Fn(){ this.x=100; this.getX=function(){ console.log(this.x); } } var f1=new Fn; f1.getX();//->方法中的this是f1->100 var ss=f1.getX; ss();//方法中的this是window->undefined
在構(gòu)造函數(shù)模式中的new Fn執(zhí)行,如果Fn不需要傳遞參數(shù)的話,后面的小括號(hào)可以省略
this的問題:在類中出現(xiàn)的this.xxx=xxx中的this都是當(dāng)前類的實(shí)例,而某一個(gè)屬性值(方法),方法中的this需要看方法執(zhí)行的時(shí)候,前面是否有“.”才能知道this是誰
function Fn(){ var num=10; this.x=100; this.getX=function(){ console.log(this.x); } } var f1=new Fn; console.log(f1.num);//=>undefined
類有普通函數(shù)的一面,當(dāng)函數(shù)執(zhí)行的時(shí)候,var num 其實(shí)只是當(dāng)前形成的私有作用域中的私有變量而已,它和我們f1這個(gè)實(shí)例沒有任何的關(guān)系,只有this.xxx=xxx才相當(dāng)于給f1這個(gè)實(shí)例增加私有的屬性和方法,才和我們的f1有關(guān)系
function Fn(){ this.x=100; this.getX=function(){ console.log(this.x); } return {name:"candy"}; } var f1=new Fn; console.log(f1);//{name:"candy"}
在構(gòu)造函數(shù)模式中,瀏覽器會(huì)默認(rèn)的把我們的實(shí)例返回(返回的是一個(gè)對(duì)象數(shù)據(jù)類型的值);如果我們自己手動(dòng)寫了return返回:
返回的是一個(gè)基本數(shù)據(jù)類型的值,當(dāng)前的實(shí)例是不變的,例如:return 100;我們的f1還是當(dāng)前fn類的實(shí)例
返回的是一個(gè)引用數(shù)據(jù)類型的值,當(dāng)前的實(shí)例會(huì)被自己返回的值給替換掉,例如:return {name:"candy"},f1就不再是fn的實(shí)例了,而是對(duì)象{name:"candy"}
function Fn(){ this.x=100; this.getX=function(){ console.log(this.x); } } var f1=new Fn; console.log(f1 instanceof Fn);//true console.log(f1 instanceof Array);//false console.log(f1 instanceof Object);//true //因?yàn)樗械膶?shí)例都是對(duì)象數(shù)據(jù)類型的,而每一個(gè)對(duì)象數(shù)據(jù)類型都是Object這個(gè)內(nèi)置類的一個(gè)實(shí)例,所以f1也是它的一個(gè)實(shí)例
檢測某一個(gè)實(shí)例是否屬于這個(gè)類->instanceof
function Fn(){ this.x=100; this.getX=function(){ console.log(this.x); } } var f1=new Fn; var f1=new Fn; console.log(f1.getX===f2.getX);//false console.log("getX" in f1);//true console.log(f1.hasOwnProperty("getX"));//ture
f1和f2都是Fn這個(gè)類的一個(gè)實(shí)例,都擁有x和getX這兩個(gè)屬性,但是這兩個(gè)屬性是各自的私有屬性
in:檢測某一個(gè)屬性是否屬于這個(gè)對(duì)象(attr in object),不管是私有的屬性還是公有的屬性,只要存在,用in來檢測都是true
hasOwnProperty:用來檢測某個(gè)屬性是否為這個(gè)對(duì)象的私有屬性,這個(gè)方法只能檢測私有的屬性
檢測某一個(gè)屬性是否為該對(duì)象的“公有屬性”->hasPubProperty
function hasPubProperty(obj,attr){ return (attr in obj) && !obj.hasOwnProperty(attr); }原型鏈模式
實(shí)例識(shí)別:構(gòu)造函數(shù)模式中擁有類和實(shí)例的概念,并且實(shí)例和實(shí)例之間是相互獨(dú)立開的原型鏈模式的三句話基于構(gòu)造函數(shù)模式的原型模式解決了 方法或者屬性公有的問題->把實(shí)例之間相同的屬性和方法提取成公有的屬性和方法(想讓誰公有就把他放在當(dāng)前類的原型上xxx.prototype即可)
每一個(gè)函數(shù)數(shù)據(jù)類型(普通函數(shù),類)都有一個(gè)天生自帶的屬性:prototype(原型),并且這個(gè)屬性是一個(gè)對(duì)象數(shù)據(jù)類型的值
并且在prototype上瀏覽器天生給他加了一個(gè)屬性constrctor(構(gòu)造函數(shù)),屬性值是當(dāng)前函數(shù)(類)本身
每一個(gè)對(duì)象數(shù)據(jù)類型(普通對(duì)象,實(shí)例,prototype...)也天生自帶一個(gè)屬性:(__proto__),這個(gè)屬性值是當(dāng)前實(shí)例所屬類的原型(prototype)
function Fn(){ this.x=100; this.sum=function(){} } Fn.prototype.getX=function(){ console.log(this.x); } Fn.prototype.sum=function(){ } var f1=new Fn; var f2=new Fn; console.log(Fn.prototype.constructor===Fn);//true
Object是JS中所有對(duì)象數(shù)據(jù)類型的基類(最頂層的類)
f1 instanceof Object->true 因?yàn)閒1通過__proto__可以向上級(jí)查找,不管有多少級(jí),最后總能找到Object
在Object.prototype上沒有__proto__這個(gè)屬性
原型鏈模式f1.hasOwnProperty("x");//hasOwnProperty是f1的一個(gè)屬性在原型模式中,this常用的有兩種情況但是我們發(fā)現(xiàn)在f1的私有屬性上沒有這個(gè)方法,那如何處理的呢?
通過對(duì)象名.屬性名的方式獲取屬性值的時(shí)候,首先在對(duì)象的私有屬性上進(jìn)行查找,如果私有中存在這個(gè)屬性,則獲取的是私有的屬性值;如果私有的沒有,則通過__proto__找到所屬類的原型(類的原型上定義的屬性和方法都是當(dāng)前實(shí)例的公有的屬性和方法),原型上存在的話,獲取的是公有的屬性值如果原型上也沒有,則繼續(xù)通過原型上的__proto__繼續(xù)向上查找,一直找到Object.prototype為止
——>這種查找的機(jī)制就是我們的原型鏈模式
**在IE瀏覽器中,我們的原型模式也是同樣的原理,但是IE瀏覽器怕你通過__proto__把公有的修改,禁止我們使__proto__
在類中this.xxx=xxx;this指的是當(dāng)前類的實(shí)例
某一個(gè)方法中他的this,看執(zhí)行的時(shí)候“.”前面是誰,this就是誰
需要先確定this的指向(this是誰)
需要把this替換成對(duì)應(yīng)的代碼
按照原型鏈查找機(jī)制,一步步的查找結(jié)果
function Fn(){ this.x=100; this.y=200; this.getY=function(){ console.log(this.y); } } Fn.prototype={ constructor:fn, y:300, getX:function(){ console.log(this.x); }, getY:function(){ console.log(this.y) } } var f=new Fn(); f.getX();//console.log(f.x)->100 f.__proto__.getX();//this是f.__proto__->console.log(f.__proto__.x)->undefined Fn.prototype.getX();//undefied f.getY();//200 f.__proto__.getY();//300
//在內(nèi)置類的原型上擴(kuò)展我們的方法: Array.prototype.myUnique=function myUnique(){ //this->ary var obj={}; for(var i=0;i批量設(shè)置公有屬性[12,13,23,24] //鏈?zhǔn)綄懛ǎ簣?zhí)行完成數(shù)組的一個(gè)方法可以緊接著執(zhí)行下一個(gè)方法 //因?yàn)閟ort是Array.prototype上的公有方法,而數(shù)組ary是Array這個(gè)類的一個(gè)實(shí)例,所以ary可以使用sort方法->數(shù)組才能是用我們Array原型上的屬性和方法
//1、起一個(gè)別名 function Fn(){ this.x=100; } var pro=Fn.prototype;//把原來原型執(zhí)行的地址賦值給我們的pro,現(xiàn)在他們操作的是同一個(gè)內(nèi)存空間 pro.getX=function(){}; pro.getY=function(){}; pro.getZ=function(){}; var f1=new Fn;
//2、重構(gòu)原型對(duì)象的方式->自己新開辟一個(gè)堆內(nèi)存,存儲(chǔ)我們公有的屬性和方法,把瀏覽器原來給的Fn.prototype開辟的那個(gè)替換掉 function Fn(){ this.x=100; } Fn.prototype={ constructor:Fn, a:function(){}, b:function(){} } var f=new Fn; f.a(); f.b(); //A、只有瀏覽器天生給的Fn.prototype開辟的堆內(nèi)存里面才有constructor,而我們自己開辟的這個(gè)堆內(nèi)存沒有這個(gè)屬性,這樣constructor指向就不是Fn而是Object了 為了和要來保持一致,我們需要手動(dòng)的增加constructor的指向 //B.給內(nèi)之類增加公有的屬性 例:Array.prototype.unique=function(){} //如果我們用上面代碼中的方法修改內(nèi)之類的話,瀏覽器會(huì)屏蔽掉,但是我們可以一個(gè)個(gè)的修改內(nèi)置的方法,當(dāng)我們通過這種方式增加方法,如果方法名和原來內(nèi)置的重復(fù)了,會(huì)把內(nèi)置的修改掉->所以在以后內(nèi)之類的原型上增加方法,命名都需要加特殊的前綴
//for in循環(huán)在遍歷的時(shí)候,默認(rèn)的話可以把自己的私有的和他所屬類原型上擴(kuò)展的屬性和方法都可以遍歷到,但是一般情況下,我們遍歷一個(gè)對(duì)象只需要遍歷私有的即可,我們可以使用以下判斷進(jìn)行處理 var obj={name:"candy",age:28} for(var key in obj){ if(obj.prototypeIsEnumberable(key)){ console.log(key); } if(obj.hasOwnProperty(key)){ console.log(key) } } //Object.create(proObj)創(chuàng)建一個(gè)新的對(duì)象,但是還要吧proObj作為這個(gè)對(duì)象的原型 在IE6~8不兼容(ECMAScript5) /*** var obj={ getX:function(){} } var obj2=Object.create(obj); obj2.getX(); obj.getY=function(){ console.log(2); } obj2.getY(); ***/ var obj={ getX:function(){ console.log(1); } }; function object(o){ function Fn(){} Fn.prototype=o; return new Fn; } var newObj=object(obj); newObj.getX();常用的六種繼承模式
原型繼承是我們JS中最常用的一種繼承方式
function A(){ this.x=100; } A.prototype.getX=function(){ console.log(this.x); } function B(){ this.y=200; this.x=200; } B.prototype=new A; B.prototype.constructor=B; var n=new B; n.getX();//200;
原型繼承的特點(diǎn):它是把父類中的私有的+公有的都繼承到子類原型上(子類公有的)
核心:原型鏈繼承并不是把父類中的屬性和方法克隆一份一模一樣的給B,而是讓B和A之間增加了原型鏈的鏈接,以后B的實(shí)例n想要用A中的getX方法,需要一級(jí)一級(jí)的向上查找
call繼承:把父類私有的屬性和方法 克隆一份一模一樣的作為子類私有的屬性
function A(){ this.x=100; } A.prototype.getX=function(){ console.log(this.x); } function B(){ A.call(this);//A.call(n) 把A執(zhí)行讓A中的this變?yōu)閚 } var n=new B; console.log(n.x);//100 n.getX();//Uncaught TypeError: n.getX is not a function
冒充對(duì)象繼承:把父類私有的+公有的 克隆一份一模一樣的給子類私有的
function A(){ this.x=100; } A.prototype.getX=function(){ console.log(this.x); } function B(){ var temp=new A; for(var key in temp){ this[key]=temp[key]; } temp=null; } var n=new B; n.getX();
function A(){ this.x=100; } A.prototype.getX=function(){ console.log(this.x); } B.prototype=objectCreate(A.prototype); B.prototype.constructor=B; var n=new B; n.getx(); function objectCreate(o){ function Fn(){ } Fn.prototype=o; return new Fn; }
混合模式繼承:原型繼承+call繼承
function A(){ this.x=100; } A.prototype.getX=function(){ console.log(this.x); } function B(){ A.call(this);//n.x=100 } B.prototype=new A;//B.prototype: x=100 getX... B.prototype.constructor=B;
function avgFn(){ Array.prototype.sort.call(arguments,function(a,b){ return a-b; }) Array.prototype.pop.call(arguments); Array.prototype.shift.call(arguments); return (eval(Array.prototype.join.call(arguments,"+")) /arguments.length).toFixed(2) } console.log(avgFn(10,20,30,10,30,40,40))
function avgFn(){ arguments.__proto__=Array.prototype; arguments.sort(function(a,b){ return a-b; }) arguments.pop(); arguments.shift(); return (eval(arguments.join("+"))/arguments.length).toFixed(2); } console.log(avgFn(10,20,30,10,30,40,40));
1.在數(shù)組的原型上有一個(gè)方法叫做slice,我們要求大家自己回去后實(shí)現(xiàn)一個(gè)方法mySlice,要求和原來的slice功能一模一樣
Array.prototype.mySlice=function mySlice(){ var ary=[]; var num=0, start=parseInt(Number(arguments[0])), end=parseInt(Number(arguments[1])); if(end===undefined||end>this.length){ end=this.length; }else if(!start){ start=0; } start>=0?null:start+=this.length; end>=0?null:end+=this.length; for(var i=start;i2、實(shí)現(xiàn)一個(gè)需求(5).plus(10).reduce(2) =>5+10-2
Number.prototype.plus=function plus(num){ return this.valueOf()+num; } Number.prototype.reduce=function reduce(num){ return this.valueOf()-num; } var m=(5).plus(10).reduce(2); console.log(m);
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/96272.html
摘要:跨域請(qǐng)求詳解從繁至簡前端掘金什么是為什么要用是的一種使用模式,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題。異步編程入門道典型的面試題前端掘金在界中,開發(fā)人員的需求量一直居高不下。 jsonp 跨域請(qǐng)求詳解——從繁至簡 - 前端 - 掘金什么是jsonp?為什么要用jsonp?JSONP(JSON with Padding)是JSON的一種使用模式,可用于解決主流瀏覽器的跨域數(shù)據(jù)訪問的問題...
摘要:本期推薦文章從作用域鏈談閉包,由于微信不能訪問外鏈,點(diǎn)擊閱讀原文就可以啦。推薦理由這是一篇譯文,深入淺出圖解作用域鏈,一步步深入介紹閉包。作用域鏈的頂端是全局對(duì)象,在全局環(huán)境中定義的變量就會(huì)綁定到全局對(duì)象中。 (關(guān)注福利,關(guān)注本公眾號(hào)回復(fù)[資料]領(lǐng)取優(yōu)質(zhì)前端視頻,包括Vue、React、Node源碼和實(shí)戰(zhàn)、面試指導(dǎo)) 本周開始前端進(jìn)階的第二期,本周的主題是作用域閉包,今天是第6天。 本...
摘要:個(gè)人前端文章整理從最開始萌生寫文章的想法,到著手開始寫,再到現(xiàn)在已經(jīng)一年的時(shí)間了,由于工作比較忙,更新緩慢,后面還是會(huì)繼更新,現(xiàn)將已經(jīng)寫好的文章整理一個(gè)目錄,方便更多的小伙伴去學(xué)習(xí)。 showImg(https://segmentfault.com/img/remote/1460000017490740?w=1920&h=1080); 個(gè)人前端文章整理 從最開始萌生寫文章的想法,到著手...
摘要:設(shè)計(jì)模式是以面向?qū)ο缶幊虨榛A(chǔ)的,的面向?qū)ο缶幊毯蛡鹘y(tǒng)的的面向?qū)ο缶幊逃行┎顒e,這讓我一開始接觸的時(shí)候感到十分痛苦,但是這只能靠自己慢慢積累慢慢思考。想繼續(xù)了解設(shè)計(jì)模式必須要先搞懂面向?qū)ο缶幊?,否則只會(huì)讓你自己更痛苦。 JavaScript 中的構(gòu)造函數(shù) 學(xué)習(xí)總結(jié)。知識(shí)只有分享才有存在的意義。 是時(shí)候替換你的 for 循環(huán)大法了~ 《小分享》JavaScript中數(shù)組的那些迭代方法~ ...
閱讀 3595·2021-11-23 09:51
閱讀 1172·2021-09-26 09:55
閱讀 4140·2021-09-22 14:58
閱讀 1932·2021-09-08 09:35
閱讀 1180·2021-08-26 14:16
閱讀 968·2019-08-23 18:17
閱讀 2220·2019-08-23 16:45
閱讀 779·2019-08-23 15:55