摘要:是班的學生構造函數的就是由這個構造函數得到的對象的原型對象父類對象構造函數的對象就是實例化對象和的原型對象。由于的所有對象都是構造函數只有除外。
前言
由于工作需求重新回顧了一下JavaScript,以下內容是我以前的學習筆記和其他參考資料整理完善后的內容,都是常用到的,使用頻率比較高的,自己必須得精通的知識點的總結,便以后再復習參考。
第一章 JavaScript原型對象與原型鏈 1.1 構造函數的缺點自定義對象時,以構造函數為模板,對象的屬性和方法,可以定義在構造函數內部。每當獲取對象時都會在內存中創建新的對象屬性和方法,這既是增加頁面代碼量有浪費內存(系統資源)。
同一個構造函數的對象實例之間無法共享屬性,而所有的方法都是同樣的行為,因此屬性和方法完全應該共享。但無法共享這就是缺點。
function Student(Name,Class){ this.name=Name; this.class=Class; this.f=function(){ console.log(this.name+"是"+this.class+"班的學生"); } } //此時,每當得到一個對象實例,就會多一個“01”的班,浪費內存, //因為只有一個班,而學生兩個,只在內存中存在一個班級而學生不一樣就可以了,但構造函數無法實現 var Stu1=new Student("Aklman","01"); var Stu2=new Student("Ahmatbek","01"); Stu1.f(); Stu2.f();1.2 prototype屬性
JavaScript中每一個對象都繼承另一個對象,父類對象稱之為“原型”(prototype)對象。只有null除外,其他都有自己的原型對象
而原型對象上的所有屬性和方法,都能被派生(子類)對象共享。通過構造方法生成生成實例化對象時,會自動生成實例化對象分配原型對象。每一個構造方法都有一個prototype屬性,這個屬性就是實例化對象的原型對象。
function Student(Name,Class){ this.name=Name; this.f=function(){ console.log(this.name+"是"+this.class+"班的學生"); } } //構造函數的prototype就是由這個構造函數得到的對象的原型對象(父類對象) Student.prototype.class="01"; var stu1=new Student("aklman"); var stu2=new Student("ahmatbek"); stu1.f(); stu2.f();
構造函數Student的prototype對象就是實例化對象stu1和stu2的原型對象。在原型對象上添加一個color屬性。結果,實例化對象都能讀取屬性。實現屬性共享;
原型對象的屬性不是實例化對象自身的屬性。但是只要修改原型對象,變動會立刻回提現到所有實例化對象上。
如果實例化對象自身就有某個屬性或方法,那么原型對象上的屬性和方法便會失效:
function Student(Name,Class){ this.name=Name; this.f=function(){ console.log(this.name+"是"+this.class+"班的學生"); } } //將class屬性,賦值給原型對象,此后所有對象共享class屬性 Student.prototype.class="01"; var stu1=new Student("aklman"); var stu2=new Student("ahmatbek"); //為stu2對象定義class屬性,原型對象的class屬性則失效,也就是說在stu2上的屬性發生變化 stu2.class="02"; stu1.f(); stu2.f();
總結:原型對象的作用就是定義所有數理化對象共享的屬性和方法。這也是他被稱為原型對象的原因,而實例化對象可以視作從原型對象衍生出來的子對象。1.3 原型鏈由于JavaScript的所有對象都是構造函數(只有null除外)。而所有構造函數都有prototype屬性(其實是所有函數都有prototype屬性),所以所有對象都有自己的原型對象。
對象的屬性和方法,有可能是定義在自身內,也有可能是定義在它的原型對象上。由于原型對象本身也是對象,又有自己的原型,所有生成了一條原型鏈(prototype chain)。例如,a對象是b對象的原型,b對象是c對象的原型,依次類推。
如果那么一層層地上溯,所有對象的原型最終都可以上溯到Object對象上。Object對象也有原型就是一個沒有任何屬性和方法的null對象,而null對象沒有自己的原型。
獲取對象的原型對象:
function Student(Name){ this.name=Name; } var stu1=new Student("aklman"); console.log(Student.prototype); console.log(Student.prototype.constructor.prototype); //由于對象自身直接獲取原型對象,最終的大對象就是object,也就是說,在JavaScript中所有對象(不管從何而來)都基于object大對象,而最大對象Object的原型指向null,也就是沒有 console.log(stu1.__pro__.__proto__.__proto__);
原型鏈的作用是讀取對象某個屬性時,JavaScript引擎先尋找對象本身的屬性,如果找不到就找它的原型(父類對象),如果還是找不到就找原型的原型。如果直到最頂層的Object。prototype還是找不到,則返回undefined。
如果對象自身和它的原型,都定義了一個同名屬性,那么悠閑讀取對象自身的屬性,這叫覆蓋(overriding)。
注意:一級級向上,在原型鏈尋找某個屬性,對性能是有影響的。如果尋找某個不存在的屬性將會遍歷整個原型鏈。
實際開發上注意事項:通常使用第三方框架(一個類),但是我們發現這個類中并不存在我們想要的屬性或方法時,不能直接修改源代碼,但是可以通過原型對象來添加我們想要的屬性和方法。
1.4 原型操作 1.4.1 constructor屬性對象有一個constructor屬性指向原型對象所在的構造函數:
function Student(name){ this.name=name; } var stu=new Student("aklman"); console.log(stu.constructor);1.4.2 設置獲取原型對象
Object.getPrototypeOf()方法返回一個對象的原型對象,也就是通過它獲取原型對象,這是標準的方法。
function Student(name,Class){ this.name=name; } var stu=new Student("aklman"); //獲取stu對象的原型對象 var s=Object.getPrototypeOf(stu); console.log(s);
Object.setPrototypeOd()為現有對象設置原型對象,第一個參數是現有對象,第二個是要設置成為原型對象的對象,用這個方法來設置原型對象。
function Student(name,Class){ this.name=name; } var ob={p:"aklan"}; var stu=new Student("Jappar"); //設置stu的原型對象ob Object.setPrototypeOf(stu,ob); console.log(stu.p);//aklman console.log(stu.name);//Jappar console.log(Object.getPrototypeOf(stu));//由大對象提供的getPrototypeOf方法獲取對象的原型對象
proto屬性:前面用proto來獲取原型對象,如果給proto屬性賦值,則設置原型對象;最好不用這個,用Object.getPrototypeOf()來讀取,用Object.setPrototypeof()來設置。也就是用這兩個方法來對原型對象做讀寫操作。
1.4.3 獲取原型對象方法及比較上面寫過獲取原型對象的方法有三種:
obj.__proto__ obj.constructor.prototype Object.getPrototypeOf(obj)
其中前兩個方法不是很友好,最新的ES6標準規定,proto屬性只有瀏覽器才需要部署,其他環境可以不部署。而obj.constructor.prototype在手動改變原型對象時,會失效。
function Student(name,Class){ this.name=name; } var ob={p:"aklman"}; var stu=new Student("Jappar"); //使用constructor屬性獲取原型對象 console.log(stu.constructor.prtototype); //修改stu的原型對象為ob Object.setPrototypeOf(stu,ob); //使用getPrototypeOf方法來查看stu的原型對象為ob console.log(Object.getPrototypeOf(stu)); //使用constructor屬性獲取原型對象為Object,這是錯誤的,構造函數無法修改對象的原型對象 console.log(stu.constructor.prototype);
總結:最好使用Object.getPrototypeOf()方法獲取原型對象,沒了。
function Student(name){ this.name=name; } vat stu=new Student("aklman"); //1.構造函數獲取原型對象 console.log(stu.constructor.prototype); //2.由對象自身獲取原型對象 console.log(stu.__proto__); //3.有大樹提供的getPrototypeOf()方法獲取對象的原型對象 console.log(Obj.getPrototypeOf(stu));第二章 閉包 2.1 閉包的概念
JavaScript有兩種作用域:全局作用域和函數作用域(局部作用域)。函數內部可以直接讀取全局變量,但是函數外部無法讀取函數內部聲明的變量。
但是,有時候卻需要在函數外部訪問函數內部的變量;正常情況下,這是無法的訪問的,只有通過變通方法才能實現訪問,也就是在函數內部再定義一個函數,通過內部函數來訪問函數內部的變量。
function fun1(){ var n=100; var fun2=function(){ console.log(n); } return funct; } var pack=fun1(); pack();//100
說明:函數fun2就在函數fun1()內部,這是fun1()內部的所有局部變量對fun2()是可訪問的。反過來就不行,內部函數中的局部變量對父類函數是不可訪問的。這就是JavaScript中特有的鏈式作用域(chain scope)結構,子對象會一級一級地向上尋找所有父類對象的變量,所以,父對象的所有變量,對子對象都是可見的,反之則不成立。
既然fun2()可以讀取fun1()中的局部變量,那么只要把fun2()作為返回值,我們就可以在fun1()外部讀取它的內部變量了。
重點:
閉包就是函數fun2,既能狗讀取其他函數內部變量的函數。由于JavaScript中,只要函數內部的子函數才能夠讀取函數內部的局部變量,因此可以把閉包簡單理解成“定義一個函數內部的函數”。2.2 垃圾回收機制及閉包 2.2.1 垃圾回收機制閉包的最大特點就是它可以“記住”誕生的環境,比如fun2()記住,所以從fun2()可以得到fun1()的內部變量。本質上,閉包就是將函數內部和函數外部連接起來的一座橋梁。
function fun1(){ var n=100; console.log(++n); } fun1();//101 fun1();//101
說明:在函數內部引入一個變量或者函數時,系統都會開辟一塊內存空間;還會將這塊內存的引用計數器初始化,初始化值為0;如果外部有全局變量或者程序引用了這塊空間,則引用計數器會自動進行+1操作,當函數執行完畢后,變量計數器會重新歸零,系統會運行垃圾回收機制,將函數運行產生的數據銷毀;如果計數器不是0,則不會清楚數據;這過程就是JavaScript的垃圾回收機制;
JavaScript的垃圾回收機制原理圖:
用閉包的分析話更能體驗此原理:
function fun1(){ var n=100; function fun2(){ console.log(++n); } return fun2; } var fu=fun1();//實際上返回了fun2 fu();//101,相當于調用了fun2(), fu();//102,相當于在此調用了fun2() fu();//103 fu();//104
代碼分析(注釋):
因函數fun1被調用時,返回的結果是fun2函數體,也就是說,fun2函數被當做返回值給fun1的調用者,但是fun2函數并沒有在此被調用執行(只是把函數體返回到函數外了);因此整個fun1函數體,無法判斷子函數fun2會對其產生何種影響,無法判斷變量n是否會被使用,即使fun1函數被調用結束,整個fun1函數始終保留在內存中,不會被垃圾回收機制回收;
也就是運行代碼發現,函數調用一次(在這里是指fun2),其變量n變化一次;
閉包的最大用處:
可以讀取函數內部的變量。讓函數內部讀取的變量始終保持在內存中,即閉包可以使得它誕生環境一直存在。
注意的是,外層函數每次運行,都會生成一個新的閉包,而這個閉包有會保留外層函數的內部變量,所以內存消耗很大;因此不能濫用閉包,否則會造成網頁的性能問題。
第三章 call和apply方法關于JavaScript中的this的指向:
1.全局作用域下,this指向window對象2.構造函數中,this指向實例化對象
如果要在調用函數是直接修改函數內部的this指向使用call或者apply方法來修改指向。
1.call方法格式:函數名稱.call(obj,arg1,arg2,...argN);說明其中:obj是函數內this要指向的對象,arg列表是參數列表,參數與參數之間使用一個逗號隔開
var ob1={name:"Aklman",age:23}; var ob2={name:"ahmatbek"}; function fun(sex){ console.log(this.name+this.age+sex); } fun.call(ob1,"男");//Aklman23男 fun.call(ob2,"男");//ahmatbekundefined男,因為對象ob2中沒有age屬性
2.apply方法格式:函數名稱.apply(obj,[arg1,,arg2,...argN]);說明其中:obj是函數內this要指向的對象,arg列表是參數列表,要求格式為數組
var ob1={name:"aklman",age:23}; var ob2={name:"ahmatbek",tel:176}; function fun(sex,age,tel){ console.log(this.name+age+sex+tel); } fun.apply(ob1, ["男", 23, 176]);//aklman23男176 fun.apply(ob2, ["男", 20, 133]);//ahmatbek20男133
兩種修改this指向方法的區別:
相同點:功能完全一樣,都是為了改變函數內部的hits指向,唯一的不同就在于參數傳遞方式不同第四章 私有屬性不同點:call方法可能多個參數,第一個要指向的對象,其他參數為函數的實參;apply方法最多只能有兩個實參,第一個要指向的對象,第二個是數組,數組內容為函數的實參。
JavaScript與其他語言不太一樣,它只有兩種屬性,即公有屬性和私有屬性,概念很好理解,也就是在構造函數內部通過this聲明的屬性就是公有屬性,通過var聲明的就是私有屬性。
function Employee(){ this.name="aklman";//公有屬性 var age=18;//私有屬性 this.fun=function(){//公有方法 console.log(this.name+age);//age只能在構造函數內部訪問 } } var m=new Employee(); console.log(m.name);//aklman console.log(m.age);//undefined m.fun();//aklman18第五章 對象繼承
JavaScript中的繼承的實現與其他語言也不相同,它沒有關鍵字提供繼承的功能。所謂繼承就是為了子類中提供父類中的屬性和方法,子類能夠使用父類中的屬性和方法;
JavaScript中繼承的實現方式有:
1.通過原型對象實現繼承
//聲明構造函數 function Study(){ this.fun=function(){ console.log("我是構造函數中的公有方法"); } } //聲明構造函數 function Student(){} Student.prototype=new Study();//設置構造函數Student的原型為Study,實現繼承 var extend=new Study(); extend.fun();
2.通過call或apply方法繼承(實質就是改變指向使用父類中的屬性和方法)
//聲明構造函數 function Study(){ this.fun=function(){ console.log("我是構造函數中的公有方法"); } } //聲明構造函數 function Student(){ Study.call(this);//將Study函數內部的this指向Student的實例化對象 } var extend=new Study(); extend.fun();第六章 定時器
JavaScript提供定時執行代碼的功能叫做定時器;
1.setTimeout():用來指定某個函數或某代碼,在多少秒之后執行。2.setInterval():指定某個任務每隔一段時間就執行一次,也就是無限次的定時執行。
setTimeout(),setInterval()的第一個參數都是指定執行的函數名稱或者代碼段,第二個參數是時間:
function fun(){ var n=1; return function(){ console.log(++n); } } var s=fun(); //3秒后調用函數; setTimeout("s()",3000); //每隔1秒就執行函數名為s的函數 setInterval(s,100);
setTimeout()函數和setInterval()函數都返回一個表示計數器編號的整數值,將該整數傳入clearTimeout()和clearInterval()函數,就可以取消對應的定時器。
補充知識點
上面提過內存,計數器,那么就谷歌一下什么是內存及計數器。
通常說的內存是計算機的主存儲器(main memory),簡稱主存。主存通過控制芯片等與CPU相連,主要負責存儲指令和數據。主存由可讀寫的元素構成,每個字節(1字節=8位)都帶有一個地址編號(也就是所謂的內存地址)。CPU可以通過改地址讀取主存中的指令和數據,當然也可以寫入數據。注意的是,主存中存儲的指令和數據會隨著計算機的關機自動清除(自動銷毀,釋放)。
寄存器是CPU的組件之一,,CPU由控制器,運算器,時鐘,寄存器組成。控制器做的是數據運算以外的處理(主要是輸入和輸出的時機控制),比如內存和磁盤等媒介的輸入輸出,顯示器,打印機的輸出等,都是控制器做的事。
廢話不多說,聽大師們說CPU中程序員只要搞明白寄存器就可以飛上天了。原因是程序是把寄存器作為對象來描述,也就是計算機中每一句命令都是通過寄存器才能執行(數據存儲,假發運算等),寄存器也有很多種類,根據類型存儲的數據也不一樣,不同的CPU中的寄存器數量也不一樣以及寄存器存儲的數值范圍也不一樣。
寄存器由程序計數器,標志寄存器,累加寄存器,基址寄存器,變址寄存器,通用寄存器等組成,其中程序計數器和標志寄存器比較特殊。計數器以二進制形式技術,計數規則是:CPU每執行一個命令,計數器的值就會自動加1,例如,CPU執行0100地址的指令后,計數器的值就變成了0101(當執行的指令占據多個內存地址是,增加與指令長度相應的數值)。然后CPU的控制器就會參照計數器的數值,從內存中讀取命令并執行,也就是說,程序計數器決定著程序的運行流程。
參考資料W3school
菜鳥教程
JavaScript權威指南(第6版)
計算機科學導論(第三版)
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/28416.html
摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復雜性。異步編程入門的全稱是前端經典面試題從輸入到頁面加載發生了什么這是一篇開發的科普類文章,涉及到優化等多個方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結思考,循序漸進的理解 TypeScript。 網絡基礎知識之 HTTP 協議 詳細介紹 HTT...
摘要:是班的學生構造函數的就是由這個構造函數得到的對象的原型對象父類對象構造函數的對象就是實例化對象和的原型對象。由于的所有對象都是構造函數只有除外。 前言 由于工作需求重新回顧了一下JavaScript,以下內容是我以前的學習筆記和其他參考資料整理完善后的內容,都是常用到的,使用頻率比較高的,自己必須得精通的知識點的總結,便以后再復習參考。 第一章 JavaScript原型對象與原型鏈 1...
摘要:是班的學生構造函數的就是由這個構造函數得到的對象的原型對象父類對象構造函數的對象就是實例化對象和的原型對象。由于的所有對象都是構造函數只有除外。 前言 由于工作需求重新回顧了一下JavaScript,以下內容是我以前的學習筆記和其他參考資料整理完善后的內容,都是常用到的,使用頻率比較高的,自己必須得精通的知識點的總結,便以后再復習參考。 第一章 JavaScript原型對象與原型鏈 1...
摘要:首次運行代碼時,會創建一個全局執行上下文并到當前的執行棧中。執行上下文的創建執行上下文分兩個階段創建創建階段執行階段創建階段確定的值,也被稱為。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,,今天是第一天 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進...
摘要:進階期理解中的執行上下文和執行棧進階期深入之執行上下文棧和變量對象但是今天補充一個知識點某些情況下,調用堆棧中函數調用的數量超出了調用堆棧的實際大小,瀏覽器會拋出一個錯誤終止運行。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,今天是第3天。 本計劃一共28期,每期重點攻...
閱讀 3209·2023-04-26 02:27
閱讀 2138·2021-11-22 14:44
閱讀 4082·2021-10-22 09:54
閱讀 3195·2021-10-14 09:43
閱讀 748·2021-09-23 11:53
閱讀 12675·2021-09-22 15:33
閱讀 2704·2019-08-30 15:54
閱讀 2681·2019-08-30 14:04