你不知道的 javascript【推薦】
一、對(duì)象
JavaScript簡(jiǎn)單類(lèi)型有數(shù)字、字符串、布爾值、null、undefined,其他所有的值都是對(duì)象(數(shù)組、函數(shù)、正則表達(dá)式都是對(duì)象)。
數(shù)字、字符串、布爾值雖然擁有方法(包裝對(duì)象),但并不是對(duì)象。
包裝對(duì)象:
每當(dāng)讀取一個(gè)基本類(lèi)型值的時(shí)候,后臺(tái)會(huì)創(chuàng)建一個(gè)對(duì)象的基本包裝類(lèi)型的對(duì)象,從而能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù)。
var s1 = 'abcdefg' ; var s2 = s1.substring(2) ;
后臺(tái)自動(dòng)完成下列處理:
- 創(chuàng)建String類(lèi)型的一個(gè)實(shí)例
- 在實(shí)例上調(diào)用指定的方法
- 銷(xiāo)毀這個(gè)實(shí)例
所以上面代碼等同于:
對(duì)象字面量
var flight = { airline: "Oceanic", number: 815, departure: { IATAL: "SYD", time: "2004-09-22 14:55", city: "Sydney" }, arrival: { IATA: "LAX", time: "2004-09-23 10:42", city: "Los Angeles" } }
檢索
[] : flight['number'] . : flight.number
更新
通過(guò)賦值語(yǔ)句更新,如果屬性名已經(jīng)存在于對(duì)象中,則被替換;如果對(duì)象中沒(méi)有那個(gè)屬性名,則添加。
stooge['first-name'] = 'Jerome'
引用
對(duì)象賦值通過(guò)引用來(lái)傳遞,它們永遠(yuǎn)不會(huì)被拷貝。
var a = { name: 'a' } var b = a b.name = 'b' console.log(a.name) // b
這里牽扯出 JavaScript 深拷貝和淺拷貝的問(wèn)題
上例是淺拷貝使用Object.create可以進(jìn)行深拷貝
var a = { name: 'a' } var b = Object.create(a) b.name = 'b' console.log(a.name) // a
自定義方法深拷貝見(jiàn)下:
var deepCopy= function(source) { var result={}; for (var key in source) { result[key] = typeof source[key]==='object'? deepCoyp(source[key]): source[key]; } return result; }
此時(shí) var b = deepCopy(a) 得到的 b 就和 a 沒(méi)有引用關(guān)系,即修改 b 不會(huì)影響 a了
原型
每個(gè)對(duì)象都連接到一個(gè)原型對(duì)象,并且從中繼承屬性。所有通過(guò)對(duì)象字面量創(chuàng)建的對(duì)象都連接到 Object.prototype 這個(gè)JavaScript中標(biāo)準(zhǔn)的對(duì)象。
創(chuàng)建一個(gè)對(duì)象時(shí),可以選擇某個(gè)對(duì)象作為它的原型:
var o = {o1:1,o2:function(){alert(1)}} function F(){} F.prototype = o var f = new F()
反射
使用 hasOwnProperty 檢查屬性是否是對(duì)象獨(dú)有的,它并不會(huì)檢查原型鏈。
flight.hasOwnProperty('number'); //true
枚舉
for in 可以遍歷對(duì)象中所有的屬性名(見(jiàn)深拷貝部分)
刪除
delete 可以刪除對(duì)象屬性,不會(huì)觸及原型鏈中的任何對(duì)象
減少全局變量污染
最小化使用全局變量的一個(gè)方法是創(chuàng)建唯一一個(gè)全局變量:
var App = {} App.stooge = { "first-name": "Joe", "last-name": "Howard" } App.flight = { airline: "Oceanic", number: 815 }
減少全局變量污染另一個(gè)辦法是使用閉包進(jìn)行信息隱藏
二、函數(shù)
函數(shù)包含一組語(yǔ)句,是Javascript的基礎(chǔ)模塊單元,用于代碼復(fù)用、信息隱藏和組合調(diào)用。
一般來(lái)說(shuō),所謂編程就是將一組需求分解成一組函數(shù)與數(shù)據(jù)結(jié)構(gòu)的技能。
函數(shù)對(duì)象
函數(shù)就是對(duì)象,對(duì)象是鍵值對(duì)的集合并且擁有一個(gè)連到原型對(duì)象的隱藏連接。對(duì)象字面量產(chǎn)生的對(duì)象連接到 Object.prototype ,函數(shù)對(duì)象連接到 Function.prototype (該原型對(duì)象本身又連接到 Object.prototype)。
var add = function(a,b){ return a + b; }
函數(shù)表達(dá)式包含四部分:
- 保留字 function
- 函數(shù)名,可以被省略(匿名函數(shù))
- 參數(shù),逗號(hào)分隔
- 花括號(hào)中的語(yǔ)句
函數(shù)表達(dá)式允許出現(xiàn)在任何允許表達(dá)式出現(xiàn)的地方,函數(shù)也可以被定義在其他函數(shù)中。一個(gè)內(nèi)部函數(shù)可以訪問(wèn)自己的參數(shù)和變量,同時(shí)它也能方便地訪問(wèn)它被嵌套在其中的那個(gè)函數(shù)的參數(shù)和變量。通過(guò)函數(shù)表達(dá)式創(chuàng)建的函數(shù)對(duì)象包含一個(gè)連到外部上下文的連接,被稱(chēng)為閉包。
調(diào)用
函數(shù)在調(diào)用的時(shí)候有兩個(gè)附加參數(shù):this、arguments。
this 是調(diào)用上下文,值取決于函數(shù)調(diào)用的模式。
1.方法調(diào)用模式
一個(gè)函數(shù)被保存為對(duì)象的一個(gè)屬性時(shí),即為一個(gè)方法。當(dāng)一個(gè)方法被調(diào)用時(shí),this 被綁定到該對(duì)象。
每個(gè)函數(shù)在創(chuàng)建時(shí)附有兩個(gè)附加的隱藏屬性:
- 函數(shù)上下文
- 實(shí)現(xiàn)函數(shù)行為的代碼
每個(gè)函數(shù)對(duì)象在創(chuàng)建時(shí)也會(huì)帶一個(gè) prototype 屬性,它的值是一個(gè)擁有 constructor 屬性且值為該函數(shù)的對(duì)象。
函數(shù)表達(dá)式
函數(shù)對(duì)象可以通過(guò)函數(shù)表達(dá)式來(lái)創(chuàng)建:
var dog = { name : 'xxx' , leg:{ sum : 4 , move:function(){ console.log(this) ; //Object,是leg對(duì)象,而不是dog對(duì)象,下面證明了 alert(this.name) ; //underfined alert(this.sum) ; //4 } } } dog.leg.move();
2.函數(shù)調(diào)用模式
函數(shù)僅僅當(dāng)做函數(shù)來(lái)調(diào)用時(shí),this 被綁定到全局對(duì)象。
var a = 111 ; function t1(){ var a = 1 function t2(){ console.log(this.a) //111,這其實(shí)很不合理,應(yīng)該指向t2的。 } t2() } t1()
這其實(shí)是語(yǔ)言設(shè)計(jì)上的一個(gè)錯(cuò)誤,倘若語(yǔ)言設(shè)計(jì)正確,當(dāng)內(nèi)部函數(shù)被調(diào)用時(shí),this 應(yīng)該仍然綁定到外部函數(shù)的 this 變量。
3.構(gòu)造器調(diào)用模式
如果一個(gè)函數(shù)前面帶上 new 調(diào)用,那么將創(chuàng)建一個(gè)隱藏連接到該函數(shù)的 prototype 成員的新對(duì)象,同時(shí) this 將被綁定到那個(gè)新對(duì)象上。
function Dog(name){ this.name = name ; } Dog.prototype.cry = function(){ alert(this.name) } var dog1 = new Dog('xxx'); dog1.cry(); // 'xxx'
4.Apply/Call調(diào)用模式
apply 接受兩個(gè)參數(shù),第一個(gè)是將被綁定給this的值,第二個(gè)就是一個(gè)參數(shù)數(shù)組。
call 與 apply 相同,不過(guò)第二個(gè)參數(shù)不是數(shù)組。
var dog = { leg : 4 , color:'yellow' } var color = 'red' ; function t(){ alert(this.color) ; } t(); // red , 因?yàn)橹赶騮his在函數(shù)中調(diào)用指向window t.call(dog); //yellow , 把t()的作用域指向了dog
再來(lái)說(shuō)說(shuō) arguments,它是一個(gè)類(lèi)數(shù)組對(duì)象(擁有l(wèi)ength屬性,但缺少所有數(shù)組方法)。通過(guò)它可以訪問(wèn)函數(shù)調(diào)用時(shí)傳遞給函數(shù)的參數(shù)列表。
返回
一個(gè)函數(shù)調(diào)用時(shí),將暫停當(dāng)前函數(shù)的執(zhí)行,傳遞控制權(quán)和參數(shù)給新函數(shù)。它從第一個(gè)語(yǔ)句開(kāi)始執(zhí)行,并在遇到關(guān)閉函數(shù)體的 } 時(shí)結(jié)束。使得函數(shù)把控制權(quán)交還給調(diào)用該函數(shù)的程序部分。
return 語(yǔ)句可用來(lái)使函數(shù)提前返回,當(dāng) return 執(zhí)行時(shí),函數(shù)立即返回而不再執(zhí)行余下的語(yǔ)句。一個(gè)函數(shù)總是會(huì)返回一個(gè)值,如果沒(méi)有指定返回值,則返回 undefined 。
如果函數(shù)前加上 new 來(lái)調(diào)用,且返回值不是一個(gè)對(duì)象,則返回this(該新對(duì)象)。
異常
拋出異常
function add(a,b){ if(typeof a!=='number' || typeof b!=='number'){ throw { name: 'TypeError', message: 'add needs numbers' } } return a + b; }
throw 語(yǔ)句中斷函數(shù)的執(zhí)行,拋出一個(gè) exception 對(duì)象,該對(duì)象包含可識(shí)別異常類(lèi)型的 name 屬性和一個(gè)描述性的 message 屬性。
該 exception 對(duì)象將被傳遞到一個(gè) try 語(yǔ)句的 catch 從句
try{ add('seven') }catch(e){ console.log(e.name) console.log(e.message) }
如果在 try 代碼塊中拋出異常,控制權(quán)就跳轉(zhuǎn)到其 catch 從句。
給類(lèi)型增加方法
Number.prototype.integer = function(){ return Math[this < 0 ? 'ceiling' : 'floor'](this) //this指向?qū)嵗? } var num = 10/3 console.log(num.integer()) ; // 3
作用域
作用域空間那個(gè)值變量和參數(shù)的可見(jiàn)性和生命周期,對(duì)程序員來(lái)說(shuō)很重要,因?yàn)樗鼫p少了命名沖突,并且提供了自動(dòng)內(nèi)存管理。
JavaScript沒(méi)有塊級(jí)作用域,卻有函數(shù)作用域:定義在函數(shù)中的參數(shù)和變量在函數(shù)外部是不可見(jiàn)的,而且在一個(gè)函數(shù)中的任何位置定義的變量在該函數(shù)中任何地方都可見(jiàn)。
下面這個(gè)例子與以對(duì)象字面量初始化對(duì)象不同,通過(guò)調(diào)用一個(gè)函數(shù)形式去初始化對(duì)象,返回一個(gè)對(duì)象字面量。此函數(shù)定義了一個(gè) val 變量,該變量對(duì) addVal 和 getVal 總是可用的,但函數(shù)的作用域使得其對(duì)其他程序來(lái)說(shuō)是不可見(jiàn)的。
// 從設(shè)計(jì)模式的角度來(lái)說(shuō)這是模塊模式 var o = (function(){ var val = 0; return { addVal: function(){ val += 1 }, getVal: function(){ console.log(val) } } })()
聯(lián)想到之前我做的一個(gè)小游戲,是20秒內(nèi)完成任務(wù),使用 restTime 做倒計(jì)時(shí)變量。后來(lái)同事把restTime修改了,成績(jī)賊高。最后我就是用這種辦法把 restTime像 val 一樣隱藏了起來(lái)。
閉包
作用域的好處是內(nèi)部函數(shù)可以訪問(wèn)定義它們的外部函數(shù)的參數(shù)和變量(除了this和arguments)。
var o = function(){ var val = 0; return { addVal: function(){ val += 1 }, getVal: function(){ console.log(val) } } } var oo = o() oo.addVal() oo.addVal() oo.getVal() // 2
當(dāng)調(diào)用 o 時(shí),返回一個(gè)包含addVal和getVal的新對(duì)象,該對(duì)象的引用保存在 oo 中。雖然 o 返回了,但是 oo 的addVal和getVal有訪問(wèn) val 的特權(quán),它們可以訪問(wèn)被創(chuàng)建時(shí)所處的上下文,這就是閉包。
模塊
可以使用函數(shù)和閉包來(lái)構(gòu)造模塊。模塊是一個(gè)提供接口卻隱藏狀態(tài)與實(shí)現(xiàn)的函數(shù)或?qū)ο蟆?/p>
具體見(jiàn)『作用域』部分-模塊模式
三、繼承
當(dāng)一個(gè)函數(shù)對(duì)象被創(chuàng)建時(shí),F(xiàn)unction 構(gòu)造器產(chǎn)生的函數(shù)對(duì)象會(huì)運(yùn)行類(lèi)似這樣的代碼:
this.prototype = {constructor: this}
每個(gè)函數(shù)都會(huì)得到一個(gè) prototype 對(duì)象,其值是包含一個(gè) constructor 屬性且屬性值為該新函數(shù)對(duì)象。該 prototype 對(duì)象是存放繼承特征的地方。
四、數(shù)組
區(qū)分?jǐn)?shù)組和對(duì)象
一個(gè)常見(jiàn)的錯(cuò)誤是在須使用數(shù)組時(shí)使用了對(duì)象,在須使用對(duì)象時(shí)使用了數(shù)組。其實(shí)規(guī)則很簡(jiǎn)單:當(dāng)屬性名是小而連續(xù)的整數(shù)時(shí),用數(shù)組,否則就用對(duì)象。
JavaScript中數(shù)組 typeof 返回是 object,這并不能區(qū)分?jǐn)?shù)組和對(duì)象。
var is_array = function(value){ return value && typeof value === 'object' && typeof value.length === 'number' && typeof value.splice === 'function' && !(value.propertyIsEnumerable('length')) }
- 首先,我們判斷這個(gè)值是否為真,我們不接受 null 和其他為假的值。
- 其次,我們判斷這個(gè)值的 typeof 運(yùn)算結(jié)果是否是 object 。對(duì)于對(duì)象、數(shù)組和null來(lái)說(shuō),將得到 true。
- 第三,我們判斷這個(gè)值是否有一個(gè)值為數(shù)字的 length 屬性,對(duì)于數(shù)組是 true ,對(duì)于對(duì)象則為 false
- 第四,判斷這個(gè)值是否包含一個(gè) splice 方法。對(duì)于數(shù)組,返回 true
- 最后,我們判斷 length 屬性是否是可枚舉的
這真的很復(fù)雜,實(shí)際上,我一直是這樣用的,什么類(lèi)型都能檢測(cè),堪稱(chēng)萬(wàn)能:
var toString = Object.prototype.toString function isObject(obj) { return toString.call(obj) === "[object Object]" } function isString(obj) { return toString.call(obj) === "[object String]" } function isArray(obj) { return toString.call(obj) === "[object Array]" } function isFunction(obj) { return toString.call(obj) === "[object Function]" }
五、方法
Array
concat(item...)
返回一個(gè)新數(shù)組,并不會(huì)修改原數(shù)組
var a1 = [2,3] var a2 = [332,12] console.log( a1.concat(a2) ); //[ 2, 3, 332, 12 ]
join(separator)
把一個(gè) array 構(gòu)造成一個(gè)字符串,并用 separator 作為分隔符把它們連接在一起。
pop(item...)
移除數(shù)組中最后一個(gè)元素并返回該元素
push(item...)
將一個(gè)或多個(gè)元素添加到數(shù)組尾部,會(huì)修改原數(shù)組
reverse()
反轉(zhuǎn)數(shù)組中元素的順序,會(huì)修改原數(shù)組,返回當(dāng)前數(shù)組
shift()
移除數(shù)組中第一個(gè)元素
slice(start,end)
從start開(kāi)始,到end為止(不包括end,可選,默認(rèn)值是length)復(fù)制數(shù)組
sort(comparefn)
對(duì)數(shù)組中的內(nèi)容排序,并不能給數(shù)字排序,因?yàn)槟J(rèn)比較函數(shù)是假定要被排序的元素都是字符串。
比較函數(shù)接受兩個(gè)參數(shù),并且如果兩個(gè)參數(shù)相等返回0,如果第一個(gè)參數(shù)應(yīng)該排在前面,則返回一個(gè)負(fù)數(shù),如果第二個(gè)參數(shù)應(yīng)該排在前面,則返回一個(gè)正數(shù)。
// a 比 b小時(shí)返回 -1,而且根據(jù)上述規(guī)則 a 會(huì)排在前面 // 所以這是從小到大的排序 var arr = [1,123,341,34,123] arr.sort(function(a,b){ if(a==b){ return 0 }else{ return a < b ? -1 : 1 } })
splice(start,deleteCount,item...)
splice 從數(shù)組中移除一個(gè)或多個(gè)元素,并用新的item代替他們。
start是從數(shù)組中移除元素的開(kāi)始位置,deleteCount是要移除的個(gè)數(shù)。
會(huì)修改原數(shù)組,返回一個(gè)包含被移除元素的數(shù)組。
var arr = [23,3,23,2] var b = arr.splice(0,1) console.log(arr) ; //[ 3, 23, 2 ] console.log(b) ; //[ 23 ]
deleteCount 為0時(shí),則為添加新元素:
var arr = [23,3,23,2] var b = arr.splice(1,0,'aa') console.log(arr) // [ 23, 'aa', 3, 23, 2 ] console.log(b) // []
deleteCount 與 item的個(gè)數(shù)相等時(shí),則為替換:
var arr = [23,3,23,2] var b = arr.splice(1,1,'aa') console.log(arr) //[ 23, 'aa', 23, 2 ] console.log(b) //[ 3 ]
unshift(item...)
將item從數(shù)組頭部插入數(shù)組
Function
apply(thisArg,argArray)
見(jiàn) 『Apply/Call調(diào)用模式』
Number
toFixed(fractionDigits)
把這個(gè) number 轉(zhuǎn)換成一個(gè)十進(jìn)制形式的字符串??蛇x參數(shù) fractionDigits 控制其小數(shù)點(diǎn)后的數(shù)字位數(shù)。
Math.PI.toFixed(); //3 Math.PI.toFixed(2); //3.14 Math.PI.toFixed(4); //3.1415
toPrecision(precision)
同 toFixed ,參數(shù)控制有效數(shù)字的位數(shù)
toString()
將number轉(zhuǎn)換成字符串
Object
hasOwnProperty(name)
只檢查此對(duì)象中的屬性,原型鏈中得同名屬性不會(huì)被檢查。如果存在此屬性則返回 true。
String
charAt(pos)
返回在字符串中pos處的字符
charCodeAt(pos)
返回不是一個(gè)字符串,而是以整數(shù)形式表示的字符碼位
concat(string...)
與其他字符串連接起來(lái)構(gòu)造一個(gè)新字符串,不常用,因?yàn)?+ 也能滿(mǎn)足需求
indexOf(searchString,pos)
在字符串內(nèi)查找另一個(gè)字符串 searchString,如果被找到,則返回第一個(gè)匹配字符的位置,否則返回 -1 。
可選參數(shù) pos 設(shè)置從字符串的某個(gè)指定位置開(kāi)始查找。
lastIndexOf(searchString,pos)
與indexOf類(lèi)似,不同從末尾開(kāi)始查找
slice(start,end)
復(fù)制字符串的一部分構(gòu)造一個(gè)新的字符串
split(separator,limit)
把字符串分割成片段創(chuàng)建數(shù)組,limit可限制被分割的片段數(shù)量。
一個(gè)有意思的技巧:
new Array(11).join('0').split('') //生成10個(gè)元素為0的數(shù)組
toLowerCase()
將字符串中所有字母轉(zhuǎn)化為小寫(xiě)
toUpperCase()
將字符串中所有字母轉(zhuǎn)化為大寫(xiě)
六、糟粕
這一部分用來(lái)吐槽JS這門(mén)語(yǔ)言設(shè)計(jì)上不周到的地方
全局變量
共三種方法定義全局變量:
- 脫離任何函數(shù)var語(yǔ)句 var foo = value
- 直接添加一個(gè)屬性到全局對(duì)象中,全局對(duì)象是所有全局變量的容器。在web中,全局對(duì)象是 window : window.foo = value
- 使用未聲明的變量,這被稱(chēng)為隱式的全局變量:foo = value
之前說(shuō)過(guò),可以通過(guò) 創(chuàng)建一個(gè)全局變量 和 閉包 減少全局變量污染(注意,只是減少,沒(méi)辦法避免,總要有暴露出來(lái)的變量,不要鉆牛角尖)。
作用域
沒(méi)有塊級(jí)作用域,只有函數(shù)作用域
自動(dòng)插入分號(hào)
JavaScript 有一個(gè)機(jī)制,會(huì)試圖通過(guò)自動(dòng)插入分號(hào)來(lái)修正有缺損的程序。它有可能會(huì)掩蓋更為嚴(yán)重的錯(cuò)誤。
return { status: true }
看起來(lái)是返回一個(gè)對(duì)象,但是自動(dòng)插入分號(hào)讓它返回了undefined,這樣可以避免:
return { status: true }
typeof
typeof并不能正確地檢測(cè)數(shù)據(jù)類(lèi)型:
typeof null ; //object
所以使用 Object.prototype.toString.call(null) 這個(gè)辦法就好,萬(wàn)能的!
以上就是本文的全部?jī)?nèi)容,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,同時(shí)也希望多多支持腳本之家!
相關(guān)文章
深入了解JavaScript中l(wèi)et/var/function的變量提升
這篇文章主要介紹了深入了解JavaScript中l(wèi)et/var/function的變量提升,文章圍繞主題展開(kāi)詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-07-07移動(dòng)端H5開(kāi)發(fā) Turn.js實(shí)現(xiàn)很棒的翻書(shū)效果
這篇文章主要為大家詳細(xì)介紹了Turn.js實(shí)現(xiàn)很棒的翻書(shū)效果,對(duì)Turn.js翻書(shū)效果的實(shí)現(xiàn)進(jìn)行總結(jié),感興趣的小伙伴們可以參考一下2016-06-06微信小程序?qū)崿F(xiàn)通過(guò)js操作wxml的wxss屬性示例
這篇文章主要介紹了微信小程序?qū)崿F(xiàn)通過(guò)js操作wxml的wxss屬性,結(jié)合實(shí)例形式分析了微信小程序使用js操作wxml的wxss屬性相關(guān)原理、實(shí)現(xiàn)技巧與操作注意事項(xiàng),需要的朋友可以參考下2018-12-12javascript異常處理實(shí)現(xiàn)原理詳解
這篇文章主要介紹了javascript異常處理實(shí)現(xiàn)原理詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02微信小程序云函數(shù)使用mysql數(shù)據(jù)庫(kù)過(guò)程詳解
這篇文章主要介紹了微信小程序云函數(shù)使用mysql數(shù)據(jù)庫(kù)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08js實(shí)現(xiàn)簡(jiǎn)單的聯(lián)動(dòng)菜單效果
這篇文章主要介紹了js實(shí)現(xiàn)簡(jiǎn)單的聯(lián)動(dòng)菜單效果,涉及javascript針對(duì)頁(yè)面元素的遍歷、讀取及設(shè)置技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-08-08