A22-JS里的對象

  • 全局對象 window

    ECMAScript 規(guī)定全局對象叫做 global,但是瀏覽器把 window 作為全局對象(瀏覽器先存在的)
    window 就是一個(gè)哈希表,有很多屬性。
    window 的屬性就是全局變量。
    使用window的屬性可以不加window.,
    比如window.alert('警告')可以寫成alert('警告')
    這些全局變量分為兩種:

    一種是 ECMAScript 規(guī)定的

    • global.parseInt
    • global.parseFloat
    • global.Number
    • global.String
    • global.Boolean
    • global.Object

    一種是瀏覽器自己加的屬性

    • window.alert
    • window.prompt
    • window.comfirm
    • window.console.log
    • window.console.dir
    • window.document
      // document由瀏覽器實(shí)現(xiàn),但是也有一個(gè)自己的標(biāo)準(zhǔn),那就是 DOM,它的標(biāo)準(zhǔn)由 W3C 制定
    • window.document.createElement
    • window.document.getElementById
      所有 API 都可以在 MDN 里找到詳細(xì)的資料。
  • 全局函數(shù)&簡單類型與對象的區(qū)別

    1. Number()

    • MDN
    • 阮一峰
    • Number('1') // 1 強(qiáng)制轉(zhuǎn)換
    • var n = new Number(1) // 返回一個(gè)值為1的對象
      在這里,Number()對象作為構(gòu)造函數(shù)使用,用來生成值為數(shù)值的對象。
    • 和直接賦值數(shù)字也就是簡單類型的區(qū)別:
      • 一個(gè)是簡單類型,一個(gè)是復(fù)雜類型
      • 兩者對內(nèi)存的使用不同,假設(shè)有
        var n1 = 1
        var n2 = new Number(1)
        內(nèi)存圖:
      • 包裝對象有許多便捷的操作
      • 你可以通過valueOf()來獲得n2的原始值1
      • 其它還有
        toString() // 獲得字符串形式
        toFixed() // 轉(zhuǎn)為指定位數(shù)的小數(shù),返回這個(gè)小數(shù)對應(yīng)的字符串
        toExponential() // 將一個(gè)數(shù)轉(zhuǎn)為科學(xué)計(jì)數(shù)法形式
        toPrecision() // 將一個(gè)數(shù)轉(zhuǎn)為指定位數(shù)的有效數(shù)字
        
        (10).toString() // "10"
        // toString方法可以接受一個(gè)參數(shù),表示輸出的進(jìn)制。如果省略這個(gè)參數(shù),默認(rèn)將數(shù)值先轉(zhuǎn)為十進(jìn)制,再輸出字符串;否則,就根據(jù)參數(shù)指定的進(jìn)制,將一個(gè)數(shù)字轉(zhuǎn)化成某個(gè)進(jìn)制的字符串。
        (10).toString(2) // "1010"
        (10).toString(8) // "12"
        (10).toString(16) // "a"
        
        // 上面代碼中,之所以要把10放在括號里,是為了表明10是一個(gè)單獨(dú)的數(shù)值,后面的點(diǎn)表示調(diào)用對象屬性。如果不加括號,這個(gè)點(diǎn)會被JavaScript引擎解釋成小數(shù)點(diǎn),從而報(bào)錯(cuò)。
        
        // 只要能夠讓JavaScript引擎不混淆小數(shù)點(diǎn)和對象的點(diǎn)運(yùn)算符,各種寫法都能用。除了為10加上括號,還可以在10后面加兩個(gè)點(diǎn),JavaScript會把第一個(gè)點(diǎn)理解成小數(shù)點(diǎn)(即10.0),把第二個(gè)點(diǎn)理解成調(diào)用對象屬性,從而得到正確結(jié)果。
        10..toString(2) // "1010"
        
        // 其他方法還包括
        10 .toString(2) // "1010"
        10.0.toString(2) // "1010"
        
        // toFixed方法用于將一個(gè)數(shù)轉(zhuǎn)為指定位數(shù)的小數(shù),返回這個(gè)小數(shù)對應(yīng)的字符串。
        (10).toFixed(2) // "10.00"
        10.005.toFixed(2) // "10.01"
        
        // toExponential方法的參數(shù)表示小數(shù)點(diǎn)后有效數(shù)字的位數(shù),范圍為0到20,超出這個(gè)范圍,會拋出一個(gè)RangeError。
        (10).toExponential()  // "1e+1"
        (10).toExponential(1) // "1.0e+1"
        (10).toExponential(2) // "1.00e+1"
        
        (1234).toExponential()  // "1.234e+3"
        (1234).toExponential(1) // "1.2e+3"
        (1234).toExponential(2) // "1.23e+3"
        
        // toPrecision方法的參數(shù)為有效數(shù)字的位數(shù),范圍是1到21,超出這個(gè)范圍會拋出RangeError錯(cuò)誤。
        (12.34).toPrecision(1) // "1e+1"
        (12.34).toPrecision(2) // "12"
        (12.34).toPrecision(3) // "12.3"
        (12.34).toPrecision(4) // "12.34"
        (12.34).toPrecision(5) // "12.340"
        
      • 兩種賦值方式的歷史:
        var n = new Number(1)是當(dāng)初被要求要像java才做出來的方式,實(shí)際上更受人喜歡的依然是var n = 1
        但是這樣方式無法使用Number對象的方法怎么辦,于是又有了下面的東西;
      • 基本包裝類型
        理論上基本類型是不能沒有toString()之類的方法的,然而實(shí)際上卻可以使用,
        這是因?yàn)槊慨?dāng)?shù)貐^(qū)一個(gè)基本類型值的時(shí)候,后臺就會創(chuàng)建一個(gè)對應(yīng)的基本包裝類型的對象,從而讓我們能夠調(diào)用一些方法來操作這些數(shù)據(jù),如下:
        var n = 1  // 1
        var s = n.toString()  // '1'
        // 后臺自動操作
        var temp = new Number(n)  // 創(chuàng)建一個(gè) Number 類型的實(shí)例
        temp.toString()  // 調(diào)用指定方法
        // 然后將temp.toString()的值作為n.toString()的值
        // 最后銷毀temp,釋放空間
        // 所以這是一種臨時(shí)的轉(zhuǎn)換,基本類型實(shí)際上并沒有屬性,
        
        也因此,var n = new Number(1)這種方式基本不再被大家所使用
      • 思考題
        var n = 1
        n.xxx = 2
        // 問:是否會報(bào)錯(cuò)?
        // NO!
        n.xxx  = 2 // 2
        n.xxx  // undefined
        

        解析:n.xxx = 2這段代碼執(zhí)行時(shí)新建了一個(gè)臨時(shí)變量temp以及屬性xxx儲存值2,所以不會報(bào)錯(cuò),
        但是執(zhí)行 n.xxx 的時(shí)候?yàn)g覽器顯示的卻是 undefined,這是因?yàn)?temp 是臨時(shí)創(chuàng)建出來了,使用后會立即銷毀,執(zhí)行 n.xxx 的時(shí)候上一句代碼創(chuàng)建的臨時(shí)temp已經(jīng)被銷毀了,這時(shí)候又是一個(gè)新的temp,它并沒有xxx這個(gè)屬性以及值


      • String()和Boolean()也是同理
      • 阮一峰
      • JavaScript高級程序設(shè)計(jì)第五章-5.6-基本包裝類型

    2. String()

    • MDN
    • MDN學(xué)習(xí)教程
    • 阮一峰
    • var s = 'abc'
      var s2 = new String(s)
      
      // charAt方法返回指定位置的字符,參數(shù)是從0開始編號的位置。
      s.charAt(1) // "b"
      s.charAt(s.length - 1) // "c"
      // 這個(gè)方法完全可以用數(shù)組下標(biāo)替代。
      'abc'.charAt(1) // "b"
      'abc'[1] // "b"
      // 如果參數(shù)為負(fù)數(shù),或大于等于字符串的長度,charAt返回空字符串。
      'abc'.charAt(-1) // ""
      'abc'.charAt(3) // ""
      
      // charCodeAt方法返回給定位置字符的Unicode碼點(diǎn)(十進(jìn)制表示),相當(dāng)于String.fromCharCode()的逆操作。
      'abc'.charCodeAt(1) // 98
      // 如果沒有任何參數(shù),charCodeAt返回首字符的Unicode碼點(diǎn)。
      'abc'.charCodeAt() // 97
      // 如何返回 16 進(jìn)制表示的Unicode碼點(diǎn)
      'abc'.charCodeAt(0).toString(16)
      
      // trim方法用于去除字符串兩端的空格,返回一個(gè)新字符串,不改變原字符串。
      '  hello world  '.trim()  // "hello world"
      // 該方法去除的不僅是空格,還包括制表符(\t、\v)、換行符(\n)和回車符(\r)。
      '\r\nabc \t'.trim()  // 'abc'
      
      // concat方法用于連接兩個(gè)字符串,返回一個(gè)新字符串,不改變原字符串。
      var s1 = 'abc';
      var s2 = 'def';
      s1.concat(s2) // "abcdef"
      s1  // "abc"
      s2  // "def"
      // 該方法可以接受多個(gè)參數(shù)。
      'a'.concat('b', 'c') // "abc"
      
      // slice方法用于從原字符串取出子字符串并返回,不改變原字符串。
      // 它的第一個(gè)參數(shù)是子字符串的開始位置,第二個(gè)參數(shù)是子字符串的結(jié)束位置(不含該位置)。
      'JavaScript'.slice(0, 4) // "Java"
      // 如果省略第二個(gè)參數(shù),則表示子字符串一直到原字符串結(jié)束。
      'JavaScript'.slice(4) // "Script"
      // 如果參數(shù)是負(fù)值,表示從結(jié)尾開始倒數(shù)計(jì)算的位置,即該負(fù)值加上字符串長度。
      'JavaScript'.slice(-6) // "Script"
      'JavaScript'.slice(0, -6) // "Java"
      'JavaScript'.slice(-2, -1) // "p"
      // 如果第一個(gè)參數(shù)大于第二個(gè)參數(shù),slice方法返回一個(gè)空字符串。
      'JavaScript'.slice(2, 1) // ""
      
      
    • String()有很多api,這里只寫了幾個(gè)常用的,更多詳見上面兩個(gè)鏈接

    3. Boolean()

    • MDN
    • 阮一峰
    • var b = new Boolean(true)
      b.toString()  // 'true'
      b.valueOf()  // true
      
      // 踩坑
      var f = false
      var f2 = new Boolean(false)
      if(f) { console.log(1) }
      if(f2) { console.log(2) }
      // 問:會打印出什么?
      2  // 只打印 2,因?yàn)?f2 并不是 false,因?yàn)樗且粋€(gè)對象,而對象是 true     
      // 別忘記js中只有 NAN、null、undefined、''、0是false,而對象和其它的都是true
      

    4. Object()

    • MDN
    • 阮一峰
    • var o = {}
      var o2 = new Object()
      // 這兩種寫法的結(jié)果沒有任何區(qū)別,因?yàn)?對象 本身是復(fù)雜類型,但是
      o === o2  // false
      // 這是因?yàn)樗鼈冸m然都創(chuàng)建一個(gè)空對象,但是地址并不一樣,是兩個(gè)地址不同擁有自己空間的空對象
      
  • 公共屬性(原型)

    var n = new Numer(1)
    var s = new String('a')
    var b = new Boolean(true)
    var o = new Object()
    
    // 上面4個(gè)不同的對象都有`toString()、valueOf()`屬性,可是如果每個(gè)對象都創(chuàng)建2個(gè)屬性會很浪費(fèi)內(nèi)存,
    // 所以,共用就好了
    

    那么怎么訪問公共屬性呢?每個(gè)對象的toString儲存公共屬性的toString的地址?不

    • proto
      js通過隱藏屬性__proto__屬性來訪問公共屬性,它指向了那些所有對象共有的屬性


      步驟:
      1. 首先查看自身是否是對象,如果不是就包裝對象
      2. 如果是對象就查看自身的 key 有沒有 toString,有的話就直接調(diào)用
      3. 如果沒有的話就通過__proto__查看你的共用屬性看有沒有,有的話就將你自身對應(yīng)的值打印出來
        例子:
      var o1 = {name: 'zero'}
      o1.toString()  // [object Object]
      // 依照步驟來,o1是對象,o1沒有toString,查看共有屬性,有toString,打印o1對應(yīng)的值
      // 不僅僅是o1,創(chuàng)建更多的對象也是一樣,所有的對象都有隱藏屬性`__proto__`,指向?qū)?yīng)的共有屬性
      var o2 = {}
      o1 === o2  // false
      o1.toString() === o2.toString()  // true
      
    • 如果是Number對象呢?
      var n = new Number(11)
      n.toString(16) // numer對象可以這樣,而oject對象是不能這樣toString(16)的
      


      可以看見,Number重寫了toString屬性,以及添加一部分自己的屬性,
      然后通過__proto__指向Object,對象共有屬性
      所以如同上圖,Number對象就是在第3步去Number重寫的屬性尋找,沒有的話去共有屬性找
      Number對象的__proto__指向Number重寫的共有屬性,Number重寫的共有屬性的__proto__指向?qū)ο蠊灿袑傩?/li>
    • 除了Number以外,類似的還有String、Boolean(目前所學(xué)的)


    • 原型鏈
      • 對象的屬性和方法,有可能定義在自身,也有可能定義在它的原型對象。由于原型本身也是對象,又有自己的原型,所以形成了一條原型鏈(prototype chain),就像我們上面畫的圖一樣,

      • 如果一層層地上溯,所有對象的原型最終都可以上溯到Object.prototype,即Object構(gòu)造函數(shù)的prototype屬性。Object.prototype 就是 Object對象的共有屬性,相對的,Number.prototype就是Number對象的共有屬性,而Number.prototype的proto又指向Object.prototype,也就是它的共有屬性,String和Boolean也是如此




        看這張圖,結(jié)合前面所學(xué)的數(shù)據(jù)結(jié)構(gòu),是不是很有意思,
        根節(jié)點(diǎn)是Object.prototype,三個(gè)子節(jié)點(diǎn)分別是String.prototype、Number.prototype、Boolean.prototype,
        當(dāng)你執(zhí)行var str = new String('a')時(shí),瀏覽器就會在堆中創(chuàng)建一個(gè)hash,str保存這個(gè)hash的地址,
        這個(gè)hash也就是String對象中除了你定義的屬性外還有隱藏屬性proto指向String.prototype,String.prototype又指向Object.prototype,這就完成了String API的所有綁定,
        Number和Boolean也是一樣

      • “原型鏈”的作用是,讀取對象的某個(gè)屬性時(shí),JavaScript 引擎先尋找對象本身的屬性,如果找不到,就到它的原型去找,如果還是找不到,就到原型的原型去找。如果直到最頂層的Object.prototype還是找不到,則返回undefined。

      • 如果對象自身和它的原型,都定義了一個(gè)同名屬性,那么優(yōu)先讀取對象自身的屬性,這叫做“覆蓋”(overriding)。

      • 需要注意的是,一級級向上,在原型鏈尋找某個(gè)屬性,對性能是有影響的。所尋找的屬性在越上層的原型對象,對性能的影響越大。如果尋找某個(gè)不存在的屬性,將會遍歷整個(gè)原型鏈。

      • prototype與proto


        兩者都指向共用屬性
        String.prototype 是 String 的共用屬性的引用(防止共用屬性被垃圾回收)
        s.proto 是 String 的共用屬性的引用(這是你在用共用屬性)



        proto 是對象的屬性,prototype 是函數(shù)的屬性
        它們儲存的地址相同,指向的其實(shí)是同一個(gè)對象

        // 一些燒腦的東西
        
        var obj1 = 函數(shù).prototype
        obj1.__proto__  === Object.prototype  // 等于下面
        函數(shù).prototype.__proto__ === Object.prototype
        
        var obj2 = 函數(shù)
        obj2.__proto__ === Function.prototype  // 也就是
        函數(shù).__proto__ === Function.prototype
        Function.__proto__ === Function.prototype
        Function.prototype.__proto__ === Obeject.prototype
        
        String.__proto__ === Function.prototype
        Number.__proto__ === Function.prototype
        Boolean.__proto__ === Function.prototype
        Object.__proto__ === Function.prototype
        


        總之,記住公式:
        對象.__proto__ === 函數(shù).prototype
        函數(shù).__proto__ === Function.prototype
        參考

      • 那么,Object.prototype對象有沒有它的原型呢?回答是有的,就是沒有任何屬性和方法的null對象,而null對象沒有自己的原型。

      • Object.getPrototypeOf(Object.prototype) // null
        上面代碼表示,Object.prototype對象的原型是null,由于null沒有任何屬性,所以原型鏈到此為止。
        Object.prototype 就是 Object對象的共有屬性

      • 阮一峰

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,505評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,556評論 3 418
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,463評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,009評論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,778評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,218評論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,281評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,436評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,969評論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,795評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,993評論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,537評論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,229評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,659評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,917評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,687評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,990評論 2 374

推薦閱讀更多精彩內(nèi)容