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