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