摘要:字面形式允許你在不需要使用操作符和構(gòu)造函數(shù)顯式創(chuàng)建對(duì)象的情況下生成引用值。操作符以一個(gè)對(duì)象和一個(gè)構(gòu)造函數(shù)作為參數(shù)鑒別數(shù)組有前一小結(jié)可以知道鑒別數(shù)組類型可以使用。屬性是函數(shù)獨(dú)有的,表明該對(duì)象可以被執(zhí)行。這種函數(shù)被稱為匿名函數(shù)。
引子:
1.JavaScript 中的變量類型和類型檢測(cè)
1.1原始類型
1.2引用類型
1.3內(nèi)建類型的實(shí)例化
1.4函數(shù)的字面形式
1.5正則表達(dá)式的字面形式
1.6類型檢測(cè)
1.6.1原始類型的檢測(cè)
1.6.2鑒別引用類型
1.6.3鑒別數(shù)組
1.6.4原始封裝類型
2.JavaScript 中的函數(shù)
2.1定義函數(shù)的兩種方式
2.1.1函數(shù)聲明
2.1.2函數(shù)表達(dá)式
2.2JavaScript函數(shù)的參數(shù)
2.3函數(shù)的重載
2.4函數(shù)使用最重要的3個(gè)點(diǎn)
2.4.1 this的使用
2.4.2 call和apply的使用
2.4.3 bind的使用
引子:最近看了兩本書,書中有些內(nèi)容對(duì)自己還是很新的,有些內(nèi)容是之前自己理解不夠深的,所以拿出來總結(jié)一下,這兩本書的名字如下:
JavaScript 面向?qū)ο缶?/p>
JavaScript 啟示錄
如果對(duì)于 JavaScript 面向?qū)ο缶幊汤斫獠粔蛏畹脑?,第一本書還是強(qiáng)烈推薦的。第二本書比較適合初中級(jí)的開發(fā)者閱讀。對(duì)各種知識(shí)點(diǎn)都有代碼示例。內(nèi)容中規(guī)中矩。
1.JavaScript 中的變量類型和類型檢測(cè)C#和Java等編程語言用棧存儲(chǔ)原始類型,用堆存儲(chǔ)引用類型,JavaScript則完全不同:它使用一個(gè)變量對(duì)象追蹤變量的生存期。原始值被直接保存在變量對(duì)象內(nèi),而引用值則作為一個(gè)指針保存在變量對(duì)象內(nèi),該指針指向?qū)嶋H對(duì)象在內(nèi)存中的存儲(chǔ)位置。
1.1原始類型在 JavaScript 中有5中原始類型,分別如下:
類型表達(dá)式 | 類型描述 |
---|---|
boolean | 布爾,值為 false或者 true |
number | 數(shù)字,值為任何整型或者浮點(diǎn)數(shù)值 |
string | 字符串,值由單引號(hào)或者雙引號(hào)括出的單個(gè)字符或者連續(xù)字符(JavaScript不區(qū)分字符類型) |
null | 空類型,該原始類型僅有一個(gè)值:null |
undefined | 未定義,該原始類型僅有一個(gè)值:undefined(undefined會(huì)被賦給一個(gè)還沒有初始化的變量) |
所有原始類型的值都有字面形式,字面形式是不被保存在變量中的值。
//string var name="zhiqiang"; var selection="a"; //number var count=235; var cost=1.51; //boolean var found=true; //null var object=null; //undefined var flag=undefined; var ref; console.log(ref); //undefined
原始類型的變量直接保存原始值(而不是一個(gè)指向?qū)ο蟮闹羔槪?。?dāng)將原始值賦值給一個(gè)變量時(shí),該值將被復(fù)制到變量中。也就是說,如果你使一個(gè)變量等于另一個(gè)時(shí),每個(gè)變量有它自己的一份數(shù)據(jù)拷貝。
示例代碼如下:
var color1="red"; var color2=color1;
內(nèi)存中的保存形式,如下圖:
1.2引用類型引用類型是在JavaScript中找到最能接近類的東西。引用值是引用類型的實(shí)例,也是對(duì)象的同義詞。屬性包含鍵(始終是字符串)和值。如果一個(gè)屬性的值是函數(shù),它就被稱為方法。JavaScript中函數(shù)其實(shí)是引用值,除了函數(shù)可以運(yùn)行以外,一個(gè)包含數(shù)組的屬性和一個(gè)包含函數(shù)的屬性沒有區(qū)別。
創(chuàng)建引用類型的兩種方式看下面的一段代碼:
//第一種使用new操作符 var obj1 = new Object(); // var obj2 = obj1; //第二種 var obj3 = {}
以上兩種創(chuàng)建對(duì)象的方式并沒有本質(zhì)的區(qū)別,是等價(jià)的。
那么當(dāng)我們創(chuàng)建了一個(gè)對(duì)象,且發(fā)生了賦值的時(shí)候,在內(nèi)存中發(fā)生了什么呢?
看下圖:
1.當(dāng)發(fā)生了new操作的時(shí)候,先在內(nèi)存中開辟一塊空間,存放創(chuàng)建的對(duì)象,并且使obj1指向這塊開辟的空間;
2.引用類型發(fā)生賦值的時(shí)候,僅僅是引用地址指向了內(nèi)存中的同一塊區(qū)域;
JavaScript語言有"垃圾回收"功能,所以在使用引用類型的時(shí)候無需擔(dān)心內(nèi)存分配。但是為了防止"內(nèi)存泄露"還是應(yīng)該在不實(shí)用對(duì)象的時(shí)候?qū)⒃搶?duì)象的引用賦值為null。讓"垃圾回收"器在特定的時(shí)間對(duì)那一塊內(nèi)存進(jìn)行回收。
1.3內(nèi)建類型的實(shí)例化JavaScript中的內(nèi)建類型如下:
類型 | 類型描述 |
---|---|
Array | 數(shù)組類型,以數(shù)字為索引的一組值的有序列表 |
Date | 日期和時(shí)間類型 |
Error | 運(yùn)行期錯(cuò)誤類型 |
Function | 函數(shù)類型 |
Object | 通用對(duì)象類型 |
RegExp | 正則表達(dá)式類型 |
內(nèi)建引用類型有字面形式。字面形式允許你在不需要使用new操作符和構(gòu)造函數(shù)顯式創(chuàng)建對(duì)象的情況下生成引用值。(包括字符串,數(shù)字,布爾,空類型和未定義);
1.4函數(shù)的字面形式創(chuàng)建函數(shù)的三種方式:
//第一種函數(shù)聲明 function abc(){ console.log(1); } //使用構(gòu)造函數(shù)的形式 var value = new Function("","console.log(1)"); //函數(shù)表達(dá)式 var a = function(){ console.log(1); };
使用構(gòu)造函數(shù)的方式創(chuàng)建函數(shù),不易讀,且調(diào)試不方便,不建議使用這種方式創(chuàng)建函數(shù)。
1.5正則表達(dá)式的字面形式在JavaScript中使用正則表達(dá)式有兩種方式:
var a1 = /d+/g;//使用字面形式 var a2 = new RegExp("d+","g");//使用構(gòu)造函數(shù)的形式
在JavaScript中建議使用字面形式的正則表達(dá)式,因?yàn)椴恍枰獡?dān)心字符串中的轉(zhuǎn)義字符。比如上面示例代碼中字面形式使用d而構(gòu)造函數(shù)使用的是d;
1.6類型檢測(cè) 1.6.1原始類型的檢測(cè)使用typeof運(yùn)算符可以完成對(duì)原始類型的檢測(cè),看下面的一段代碼:
上面的代碼中有一段比較特殊就是
typeof null //object
這里其實(shí)是不準(zhǔn)確的,如果我們要判斷一個(gè)值是否為空類型的最佳的方式是直接和null進(jìn)行比較
console.log(value === null);
==和===之間的最主要的區(qū)別就是前者在進(jìn)行比較的時(shí)候會(huì)進(jìn)行類型轉(zhuǎn)化,而后者不會(huì);
console.log(5==5);//true console.log("5"==5);//false console.log("5"===5);//fasle1.6.2鑒別引用類型
JavaScript中對(duì)于引用類型的檢測(cè)較為復(fù)雜。對(duì)于函數(shù)類型的引用使用typeof返回的是Function,而對(duì)于非函數(shù)的引用類型返回的則是object。所以在JavaScript中鑒別引用類型的類型引入了instanceof。
instanceof操作符以一個(gè)對(duì)象和一個(gè)構(gòu)造函數(shù)作為參數(shù);
function a (){} var b = {}; var c =[]; typeof a // function typeof b //object typeof c //object a instanceof Function //true b instanceof Object //true c instanceof Array //true1.6.3鑒別數(shù)組
有前一小結(jié)可以知道鑒別數(shù)組類型可以使用instanceof。但是在ECMAScript5中,Array對(duì)象提供了更好的方式來鑒別一個(gè)變量是不是數(shù)組類型。
var a = []; var b =3; Array.isArray(a); //true Array.isArray(b); //false
注意:IE8及更早的IE不支持該方法
1.6.4原始封裝類型JavaScript中的原始封裝類型共有3種。這些特殊引用類型的存在使得原始類型用起來和對(duì)象一樣方便。當(dāng)讀取字符串,數(shù)字,布爾類型時(shí),原始封裝類型被自動(dòng)創(chuàng)建。
var a ="qwer"; var firstChar = a.chatAt(0); console.log(firstChar);// q
在JavaScript引擎中發(fā)生了如下的過程:
var a ="qwer"; var temp = new String(a); var firstChar = temp.chatAt(0); temp =null; console.log(firstChar);// q
由于要把字符串當(dāng)成對(duì)象使用,JavaScript引擎創(chuàng)建了一個(gè)字符串實(shí)體讓charAt可以工作,字符串對(duì)象(temp)的存在僅僅用于該語句(temp.chatAt(0)),隨后便被銷毀(temp =null)。
我們可以簡(jiǎn)單測(cè)試一下
var a ="qwer"; a.temp ="122"; console.log(a.temp); //undefined
上面代碼的過程如下:
var a ="qwer"; var temp = new String(a); temp.temp ="122"; temp=null; var temp = new String(a); console.log(a.temp); //undefined temp=null;
由上面的代碼我們可以看到我們實(shí)際上是在一個(gè)立刻就會(huì)被銷毀的對(duì)象上而不是字符串上添加了一個(gè)新屬性。當(dāng)試圖訪問這個(gè)屬性時(shí),另一個(gè)不同的臨時(shí)對(duì)象被創(chuàng)建,而新屬性并不存在。雖然原始封裝類型會(huì)被自動(dòng)創(chuàng)建,但是在這些值上進(jìn)行instanceof檢查對(duì)應(yīng)類型的返回值卻都是false;
var a ="1234"; var num = 10; a instanceof String //false num instanceof Number //false
這是因?yàn)榕R時(shí)對(duì)象僅在值被讀取的時(shí)候創(chuàng)建,隨即被銷毀。instanceof操作符并沒有讀取到任何東西,也沒有臨時(shí)對(duì)象的創(chuàng)建,因此它告訴我們這些值并不屬于原始封裝類型;
但是我們可以手動(dòng)創(chuàng)建原始封裝類型,但是此時(shí)使用typeof沒辦法檢測(cè)對(duì)象的實(shí)際類型,只能夠使用instanceof來檢測(cè)變量類型;
2.JavaScript 中的函數(shù)在JavaScript中函數(shù)就是對(duì)象。函數(shù)不同于其他對(duì)象的決定性特點(diǎn)是,函數(shù)存在一個(gè)被稱為[[Call]]的內(nèi)部屬性。內(nèi)部屬性無法通過代碼訪問而是定義了代碼執(zhí)行時(shí)的行為。ECMAScript為JavaScript的對(duì)象定義了多種內(nèi)部屬性,這些內(nèi)部屬性都用雙重中括號(hào)來標(biāo)注。
[[Call]]屬性是函數(shù)獨(dú)有的,表明該對(duì)象可以被執(zhí)行。由于僅函數(shù)擁有該屬性,ECMAScript定義了typeof操作符對(duì)任何具有[[Call]]屬性的對(duì)象返回**function**>
2.1定義函數(shù)的兩種方式 2.1.1函數(shù)聲明函數(shù)聲明是以function關(guān)鍵字開頭,這也是區(qū)別函數(shù)聲明和函數(shù)表達(dá)式的一個(gè)重要的方法。函數(shù)聲明會(huì)在編譯期對(duì)整個(gè)作用域內(nèi)的變量名字進(jìn)行查詢,函數(shù)聲明的變量被提升至上下文的頂部,也就是說可以先使用函數(shù)后聲明它們。
abc(); function abc(){ console.log(2); }2.1.2函數(shù)表達(dá)式
函數(shù)表達(dá)式是function關(guān)鍵字后邊不需要加上函數(shù)的名字。這種函數(shù)被稱為匿名函數(shù)。因?yàn)楹瘮?shù)對(duì)象本身沒有名字,所以函數(shù)表達(dá)式通常會(huì)被一個(gè)變量或者屬性引用。
abcd() var abcd=function(){ console.log(1) }; var aaa={ abc:function(){ } }
函數(shù)表達(dá)式只能通過變量引用,無法提升匿名函數(shù)的作用域。在使用函數(shù)表達(dá)式之前必須先創(chuàng)建它們,否則代碼會(huì)報(bào)錯(cuò)??词纠a的運(yùn)行結(jié)果:
2.2JavaScript函數(shù)的參數(shù)JavaScript函數(shù)參數(shù)與很多語言函數(shù)參數(shù)不一樣。你可以給函數(shù)傳遞任意數(shù)量的參數(shù)卻不造成錯(cuò)誤。那是因?yàn)楹瘮?shù)實(shí)際上被保存在一個(gè)被稱為arguments的類似數(shù)組的對(duì)象中。arguments可以自由增長(zhǎng)來包含任意個(gè)數(shù)的值,這些值可以通過數(shù)字索引來引用。arguments的length屬性會(huì)告訴你目前有多少個(gè)值(函數(shù)接受了多少個(gè)參數(shù))。
arguments是一個(gè)類數(shù)組對(duì)象,它本身并不具有JavaScript數(shù)組應(yīng)該具有的全部的屬性和方法。
這里我們思考一個(gè)問題,我們?cè)趺磳⒁粋€(gè)類數(shù)組轉(zhuǎn)化為真正的數(shù)組?
最基本的我們應(yīng)該想到的是創(chuàng)建一個(gè)原始的空數(shù)組,使用for循環(huán)將類數(shù)組中的每一項(xiàng)添加到新的數(shù)組中;
如果使用Zepto或者jQuery的話,會(huì)有一個(gè)toArray()的方法可以使用;
ES6有Array.from(arrayLike[, mapFn[, thisArg]])可以將類數(shù)組轉(zhuǎn)化為數(shù)組對(duì)象;
最后一種也是最高級(jí)的一種方法就是使用原型的方式;
借用原型的方式把一個(gè)類數(shù)組轉(zhuǎn)化為真正的數(shù)組的示例代碼:
function abc(){ console.log(arguments); var arrTemp = [].slice.apply(arguments); //相當(dāng)于Array.prototype.slice == [].slice console.log(arrTemp); console.log(Array.isArray(arrTemp)); } abc(1,2,3);
輸出結(jié)果:
2.3函數(shù)的重載依稀的記得在學(xué)習(xí)的從C# 的時(shí)候,這些強(qiáng)類型語言對(duì)重載的定義:函數(shù)名相同,參數(shù)不同,或者是參數(shù)類型不同都可以叫做函數(shù)的重載。
但是在JavaScript這樣的語言中因?yàn)?arguments的存在,JavaScript的函數(shù)根本就不存在所謂的簽名,所以重載在JavaScript中實(shí)際是不存在的。
但是我們可以根據(jù)arguments傳入函數(shù)體的參數(shù)個(gè)數(shù)來模擬_函數(shù)重載_:
function abc(){ if (arguments.length ===1){ //A } if(arguments.length ===2){ //B } } abc(11); abc(11,22);
這里主要是滿足某些特殊場(chǎng)合的需求吧。
2.4函數(shù)使用最重要的3個(gè)點(diǎn)this;
apply()和call();
bind();
關(guān)于this,call,apply,bind這幾個(gè)概念在之前博客文章已經(jīng)介紹過很多遍了。在這里還是做一下簡(jiǎn)單的介紹。
2.4.1 this的使用this的指向在函數(shù)定義的時(shí)候是確定不了的,只有函數(shù)執(zhí)行的時(shí)候才能確定this到底指向誰,實(shí)際上this的最終指向的是那個(gè)調(diào)用它的對(duì)象;
this指向的對(duì)象是在代碼的運(yùn)行期決定的。既上面說的,誰調(diào)用了它,就指向誰。一個(gè)很簡(jiǎn)單的總結(jié)就是,在函數(shù)中使用this,當(dāng)前this指向的是當(dāng)前window對(duì)象。在對(duì)象的方法中使用this,this指向的是當(dāng)前對(duì)象(這個(gè)也是最容易出錯(cuò)的地方)。
2.4.2 call和apply的使用關(guān)于這兩個(gè)概念,之前的博客文章也介紹多很多次。這里也簡(jiǎn)單總結(jié)介紹一下。call和apply主要是在執(zhí)行某個(gè)對(duì)象的方法的時(shí)候來改變當(dāng)前this的指向。主要用在對(duì)象繼承的時(shí)候。
2.4.3 bind的使用bind也是改變對(duì)象this指向的一個(gè)方法。這個(gè)方法是ECMAScript5中新添加的一個(gè)方法。但是bind和call,apply的主要區(qū)別就是bind的第一個(gè)參數(shù)是要傳給新函數(shù)的this的值。其它所有參數(shù)代表需要被永久設(shè)置在新函數(shù)中的命名參數(shù)??梢栽谥罄^續(xù)設(shè)置任何非永久參數(shù)。
來看一段示例代碼:
function abc (lab){ console.log(lab + this.name); } var person1 = { name:"xiaogang" } var person2={ name:"zhiqiang21" } var sayNamePer1 =abc.bind(person1); sayNamePer1("person1"); var sayNamePer2 =abc.bind(person2,"person2"); sayNamePer2(); person2.sayName = sayNamePer1; person2.sayName("person2");
上面的代碼中:
sayNamePer1在綁定的時(shí)候沒有傳入?yún)?shù),所以仍需要后續(xù)執(zhí)行sayNamePer1來傳入lab參數(shù);sayNamePer2不僅綁定了this為person2,還綁定了輸入的第一個(gè)參數(shù)是person2。意味著可以可以直接執(zhí)行sayNamePer2()。最后一個(gè)是將sayNamePer1設(shè)置位person2的sayName方法。由于其this的值已經(jīng)綁定,所以雖然sayNamePer1是person2的方法,但是輸出的仍然是person1.name的值。
其實(shí)總結(jié)一句話call,apply和bind的主要區(qū)別就是:
call和apply是綁定既執(zhí)行。bind是有返回值的,先綁定后執(zhí)行。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/90892.html
摘要:個(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è)人前端文章整理 從最開始萌生寫文章的想法,到著手...
摘要:入門,第一個(gè)這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運(yùn)行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
摘要:入門,第一個(gè)這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數(shù)式編程語言,它的代碼運(yùn)行在之上。它通過編輯類工具,帶來了先進(jìn)的編輯體驗(yàn),增強(qiáng)了語言服務(wù)。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經(jīng)到來了,總結(jié)過去的 2017,相信小伙們一定有很多收獲...
閱讀 9056·2021-11-18 10:02
閱讀 2602·2019-08-30 15:43
閱讀 2663·2019-08-30 13:50
閱讀 1382·2019-08-30 11:20
閱讀 2712·2019-08-29 15:03
閱讀 3633·2019-08-29 12:36
閱讀 933·2019-08-23 17:04
閱讀 624·2019-08-23 14:18