<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                ## 3.3 原生函數 常用的原生函數有: ? String() ? Number() ? Boolean() ? Array() ? Object() ? Function() ? RegExp() ? Date() ? Error() ? Symbol()——ES6 中新加入的! 實際上,它們就是內建函數。 原生函數可以被當作構造函數來使用,通過構造函數(如new String("abc"))創建出來的是**封裝了基本類型值(如"abc")的封裝對象**。 ~~~ var a = new String( "abc" ); typeof a; // 是"object",不是"String" a instanceof String; // true Object.prototype.toString.call( a ); // "[object String]" ~~~ 可以這樣來查看封裝對象: ~~~ console.log( a ); ~~~ ### 3.3.1 內部屬性[[Class]] 所有`typeof `返回值為"object" 的對象(如數組)都包含一個內部屬性[[Class]](可以把它看作一個**內部的分類**,而非傳統的面向對象意義上的類)。這個屬性無法直接訪問,一般通過`Object.prototype.toString(..) `來查看。 ~~~ Object.prototype.toString.call( [1,2,3] ); // "[object Array]" Object.prototype.toString.call( /regex-literal/i ); // "[object RegExp]" ~~~ 對象的內部[[Class]] 屬性和創建該對象的內建原生構造函數相對應,但并非總是如此。 ~~~ Object.prototype.toString.call( null ); // "[object Null]" Object.prototype.toString.call( undefined ); // "[object Undefined]" ~~~ 雖然Null() 和Undefined() 這樣的原生構造函數并不存在,但是內部[[Class]] 屬性值仍然是"Null" 和"Undefined"。 其他基本類型值(如字符串、數字和布爾)的情況有所不同,通常稱為“**包裝**”(boxing)。 ~~~ Object.prototype.toString.call( "abc" ); // "[object String]" Object.prototype.toString.call( 42 ); // "[object Number]" Object.prototype.toString.call( true ); // "[object Boolean]" ~~~ 上例中基本類型值被各自的封裝對象自動包裝,所以它們的內部[[Class]] 屬性值分別為"String"、"Number" 和"Boolean"。 ### 3.3.2 封裝對象包裝 由于基本類型值沒有`.length`和`.toString()` 這樣的屬性和方法,需要通過封裝對象才能訪問,此時JavaScript 會自動為基本類型值包裝(box 或者wrap)一個封裝對象: ~~~ var a = "abc"; a.length; // 3 a.toUpperCase(); // "ABC" ~~~ #### 封裝對象釋疑 使用封裝對象時有些地方需要特別注意。 比如Boolean: ~~~ var a = new Boolean( false ); if (!a) { console.log( "Oops" ); // 執行不到這里 } ~~~ 我們為false 創建了一個封裝對象,然而該對象是真值(“truthy”,即總是返回true),所以這里使用封裝對象得到的結果和使用false 截然相反。 如果想要自行封裝基本類型值,可以使用Object(..) 函數(不帶new 關鍵字): ~~~ var a = "abc"; var b = new String( a ); var c = Object( a ); typeof a; // "string" typeof b; // "object" typeof c; // "object" b instanceof String; // true c instanceof String; // true Object.prototype.toString.call( b ); // "[object String]" Object.prototype.toString.call( c ); // "[object String]" ~~~ 一般不推薦直接使用封裝對象(如上例中的b 和c),但它們偶爾也會派上用場。 ### 3.3.3 拆封 如果想要得到封裝對象中的基本類型值,可以使用`valueOf()` 函數: ~~~ var a = new String( "abc" ); var b = new Number( 42 ); var c = new Boolean( true ); a.valueOf(); // "abc" b.valueOf(); // 42 c.valueOf(); // true ~~~ 在需要用到封裝對象中的基本類型值的地方會發生隱式拆封。具體過程(即強制類型轉換) ~~~ var a = new String( "abc" ); var b = a + ""; // b的值為"abc" typeof a; // "object" typeof b; // "string" ~~~ ### 3.3.4 原生函數作為構造函數 關于數組(array)、對象(object)、函數(function)和正則表達式,通常以常量的形式來創建它們。實際上,使用常量和使用構造函數的效果是一樣的(創建的值都是通過封裝對象來包裝)。 **1. Array()** ~~~ var a = new Array( 1, 2, 3 ); a; // [1, 2, 3] var b = [1, 2, 3]; b; // [1, 2, 3] ~~~ Array 構造函數只帶一個數字參數的時候,該參數會被作為數組的預設長度(length),而非只充當數組中的一個元素。這樣創建出來的只是一個空數組,只不過它的length 屬性被設置成了指定的值。 如若一個數組沒有任何單元,但它的length 屬性中卻顯示有單元數量,這樣奇特的數據結構會導致一些怪異的行為。而這一切都歸咎于已被廢止的舊特性(類似arguments 這樣的類數組)。 對此,不同瀏覽器的開發控制臺顯示的結果也不盡相同,這讓問題變得更加復雜。 例如: ~~~ var a = new Array( 3 ); a.length; // 3 a; ~~~ a 在Chrome 中顯示為[ undefined x 3 ](目前為止),這意味著它有三個值為undefined的單元,但實際上單元并不存在(“空單元” 這個叫法也同樣不準確)。 從下面代碼的結果可以看出它們的差別: ~~~ var a = new Array( 3 ); var b = [ undefined, undefined, undefined ]; var c = []; c.length = 3; a; b; c; ~~~ b 在當前版本的Chrome 中顯示為[ undefined, undefined, undefined ],而a 和c 則顯示為[ undefined x 3 ]。 更糟糕的是,上例中a 和b 的行為有時相同,有時又大相徑庭: ~~~ a.join( "-" ); // "--" b.join( "-" ); // "--" a.map(function(v,i){ return i; }); // [ undefined x 3 ] b.map(function(v,i){ return i; }); // [ 0, 1, 2 ] ~~~ a.map(..) 之所以執行失敗,是因為數組中并不存在任何單元,所以map(..) 無從遍歷。而join(..) 卻不一樣,它的具體實現可參考下面的代碼: ~~~ function fakeJoin(arr,connector) { var str = ""; for (var i = 0; i < arr.length; i++) { if (i > 0) { str += connector; } if (arr[i] !== undefined) { str += arr[i]; } } return str; } var a = new Array( 3 ); fakeJoin( a, "-" ); // "--" ~~~ 從中可以看出,join(..) 首先假定數組不為空,然后通過length 屬性值來遍歷其中的元素。而map(..) 并不做這樣的假定,因此結果也往往在預期之外,并可能導致失敗。 可以通過下述方式來創建包含undefined 單元(而非“空單元”)的數組: ~~~ var a = Array.apply( null, { length: 3 } ); a; // [ undefined, undefined, undefined ] ~~~ apply(..) 是一個工具函數,適用于所有函數對象,它會以一種特殊的方式來調用傳遞給它的函數。 第一個參數是this 對象,這里不用太過費心,暫將它設為null。第二個參數則必須是一個數組(或者類似數組的值,也叫作類數組對象,array-like object),其中的值被用作函數的參數。于是`Array.apply(..) `調用`Array(..)` 函數,并且將`{ length: 3 }` 作為函數的參數。 可以設想`apply(..) `內部有一個for 循環(與上述join(..) 類似),從0 開始循環到length(即循環到2,不包括3)。假設在`apply(..) `內部該數組參數名為`arr`,for 循環就會這樣來遍歷數組:arr[0]、arr[1]、arr[2]。然而, 由于{ length: 3 } 中并不存在這些屬性, 所以返回值為undefined。 換句話說,我們執行的實際上是`Array(undefined, undefined, undefined)`,所以結果是單元值為undefined 的數組,而非空單元數組。雖然`Array.apply( null, { length: 3 } ) `在創建`undefined `值的數組時有些奇怪和繁瑣,但是其結果遠比Array(3) 更準確可靠。總之,**永遠不要創建和使用空單元數組**。 **2. Object(..)、Function(..) 和RegExp(..)** 同樣,除非萬不得已,否則盡量不要使用`Object(..)/Function(..)/RegExp(..)`: ~~~ var c = new Object(); c.foo = "bar"; c; // { foo: "bar" } var d = { foo: "bar" }; d; // { foo: "bar" } var e = new Function( "a", "return a * 2;" ); var f = function(a) { return a * 2; } function g(a) { return a * 2; } var h = new RegExp( "^a*b+", "g" ); var i = /^a*b+/g; ~~~ 在實際情況中沒有必要使用new Object() 來創建對象,因為這樣就無法像常量形式那樣一次設定多個屬性,而必須逐一設定。 構造函數Function 只在極少數情況下很有用,比如動態定義函數參數和函數體的時候。 強烈建議使用常量形式(如`/^a*b+/g`)來定義正則表達式,這樣不僅語法簡單,執行效率也更高,因為JavaScript 引擎在代碼執行前會對它們進行預編譯和緩存。與前面的構造函數不同,RegExp(..) 有時還是很有用的,比如動態定義正則表達式時: ~~~ var name = "Kyle"; var namePattern = new RegExp( "\\b(?:" + name + ")+\\b", "ig" ); var matches = someText.match( namePattern ); ~~~ 上述情況在JavaScript 編程中時有發生,這時`new RegExp("pattern","flags") `就能派上用場。 **3. Date(..) 和Error(..)** 創建日期對象必須使用`new Date()`。`Date(..) `可以帶參數,用來指定日期和時間,而不帶參數的話則使用當前的日期和時間。`Date(..) `主要用來獲得當前的Unix 時間戳(從1970 年1 月1 日開始計算,以秒為單位)。該值可以通過日期對象中的getTime() 來獲得。 從ES5 開始引入了一個更簡單的方法,即靜態函數Date.now()。對ES5 之前的版本可以使用下面的polyfill: ~~~ if (!Date.now) { Date.now = function(){ return (new Date()).getTime(); }; } ~~~ 構造函數`Error(..)`(與前面的Array() 類似)帶不帶new 關鍵字都可。創建錯誤對象(error object)主要是為了獲得當前運行棧的上下文(大部分JavaScript 引擎通過只讀屬性.stack 來訪問)。棧上下文信息包括函數調用棧信息和產生錯誤的代碼行號, 以便于調試(debug)。 錯誤對象通常與throw 一起使用: ~~~ function foo(x) { if (!x) { throw new Error( "x wasn’t provided" ); } // .. } ~~~ 通常錯誤對象至少包含一個`message` 屬性,有時也不乏其他屬性(必須作為只讀屬性訪問),如type。除了訪問stack 屬性以外,最好的辦法是調用(顯式調用或者通過強制類型轉換隱式調用)`toString()` 來獲得經過格式化的便于閱讀的錯誤信息。 **4. Symbol(..)** ES6 中新加入了一個基本數據類型 ——**符號(Symbol)**。符號是具有唯一性的特殊值(并非絕對),用它來命名對象屬性不容易導致重名。該類型的引入主要源于ES6 的一些特殊構造,此外符號也可以自行定義。 符號可以用作屬性名,但無論是在代碼還是開發控制臺中都無法查看和訪問它的值,只會顯示為諸如`Symbol(Symbol.create)` 這樣的值。 ES6 中有一些預定義符號,以Symbol 的靜態屬性形式出現,如`Symbol.create、Symbol.iterator `等,可以這樣來使用: ~~~ obj[Symbol.iterator] = function(){ /*..*/ }; ~~~ 可以使用Symbol(..) 原生構造函數來自定義符號。但它比較特殊,**不能帶new 關鍵字**,否則會出錯: ~~~ var mysym = Symbol( "my own symbol" ); mysym; // Symbol(my own symbol) mysym.toString(); // "Symbol(my own symbol)" typeof mysym; // "symbol" var a = { }; a[mysym] = "foobar"; Object.getOwnPropertySymbols( a ); // [ Symbol(my own symbol) ] ~~~ 雖然符號實際上并非私有屬性(通過`Object.getOwnPropertySymbols(..)` 便可以公開獲得對象中的所有符號),但它卻主要用于私有或特殊屬性。很多開發人員喜歡用它來替代有下劃線`(_)`前綴的屬性,而下劃線前綴通常用于命名私有或特殊屬性。 **5. 原生原型** 原生構造函數有自己的`.prototype` 對象,如Array.prototype、String.prototype 等。這些對象包含其對應子類型所特有的行為特征。 例如,將字符串值封裝為字符串對象之后,就能訪問String.prototype 中定義的方法。(將`String.prototype.XYZ` 簡寫為`String#XYZ`, 對其他`.prototypes `也同樣如此。) ~~~ ? String#indexOf(..) 在字符串中找到指定子字符串的位置。 ? String#charAt(..) 獲得字符串指定位置上的字符。 ? String#substr(..)、String#substring(..) 和String#slice(..) 獲得字符串的指定部分。 ? String#toUpperCase() 和String#toLowerCase() 將字符串轉換為大寫或小寫。 ? String#trim() 去掉字符串前后的空格,返回新的字符串。 ~~~ 以上方法并不改變原字符串的值,而是返回一個新字符串。 借助原型代理(prototype delegation),所有字符串都可以訪問這些方法: ~~~ var a = " abc "; a.indexOf( "c" ); // 3 a.toUpperCase(); // " ABC " a.trim(); // "abc" ~~~ 其他構造函數的原型包含它們各自類型所特有的行為特征,比如`Number#tofixed(..)`(將數字轉換為指定長度的整數字符串)和`Array#concat(..)`(合并數組)。所有的函數都可以調用`Function.prototype 中的apply(..)、call(..) 和bind(..)`。 然而,有些原生原型(native prototype)并非普通對象那么簡單: ~~~ typeof Function.prototype; // "function" Function.prototype(); // 空函數! RegExp.prototype.toString(); // "/(?:)/"——空正則表達式 "abc".match( RegExp.prototype ); // [""] ~~~ 更糟糕的是,我們甚至可以修改它們(而不僅僅是添加屬性): ~~~ Array.isArray( Array.prototype ); // true Array.prototype.push( 1, 2, 3 ); // 3 Array.prototype; // [1,2,3] // 需要將Array.prototype設置回空,否則會導致問題! Array.prototype.length = 0; ~~~ 這里,`Function.prototype` 是一個函數,`RegExp.prototype` 是一個正則表達式,而`Array.prototype` 是一個數組。 **將原型作為默認值** `Function.prototype` 是一個空函數,`RegExp.prototype` 是一個“空”的正則表達式(無任何匹配),而`Array.prototype `是一個空數組。對未賦值的變量來說,它們是很好的默認值。 例如: ~~~ function isThisCool(vals,fn,rx) { vals = vals || Array.prototype; fn = fn || Function.prototype; rx = rx || RegExp.prototype; return rx.test( vals.map( fn ).join( "" ) ); } isThisCool(); // true isThisCool( ["a","b","c"], function(v){ return v.toUpperCase(); }, /D/ ); // false ~~~ 這種方法的一個好處是`.prototypes `已被創建并且僅創建一次。相反, 如果將`[]、function(){} 和/(?:)/ `作為默認值,則每次調用`isThisCool(..) `時它們都會被創建一次(具體創建與否取決于JavaScript 引擎,稍后它們可能會被垃圾回收),這樣無疑會造成內存和CPU 資源的浪費。 另外需要注意的一點是,如果默認值隨后會被更改,那就不要使用Array.prototype。上例中的vals 是作為只讀變量來使用,更改vals 實際上就是更改Array.prototype,而這樣會導致前面提到過的一系列問題!
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看