A22-JS里的对象

  • 全局对象 window

    ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对象(浏览器先存在的)
    window 就是一个哈希表,有很多属性。
    window 的属性就是全局变量。
    使用window的属性可以不加window.,
    比如window.alert('警告')可以写成alert('警告')
    这些全局变量分为两种:

    一种是 ECMAScript 规定的

    • 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由浏览器实现,但是也有一个自己的标准,那就是 DOM,它的标准由 W3C 制定
    • window.document.createElement
    • window.document.getElementById
      所有 API 都可以在 MDN 里找到详细的资料。
  • 全局函数&简单类型与对象的区别

    1. Number()

    • MDN
    • 阮一峰
    • Number('1') // 1 强制转换
    • var n = new Number(1) // 返回一个值为1的对象
      在这里,Number()对象作为构造函数使用,用来生成值为数值的对象。
    • 和直接赋值数字也就是简单类型的区别:
      • 一个是简单类型,一个是复杂类型
      • 两者对内存的使用不同,假设有
        var n1 = 1
        var n2 = new Number(1)
        内存图:
      • 包装对象有许多便捷的操作
      • 你可以通过valueOf()来获得n2的原始值1
      • 其它还有
        toString() // 获得字符串形式
        toFixed() // 转为指定位数的小数,返回这个小数对应的字符串
        toExponential() // 将一个数转为科学计数法形式
        toPrecision() // 将一个数转为指定位数的有效数字
        
        (10).toString() // "10"
        // toString方法可以接受一个参数,表示输出的进制。如果省略这个参数,默认将数值先转为十进制,再输出字符串;否则,就根据参数指定的进制,将一个数字转化成某个进制的字符串。
        (10).toString(2) // "1010"
        (10).toString(8) // "12"
        (10).toString(16) // "a"
        
        // 上面代码中,之所以要把10放在括号里,是为了表明10是一个单独的数值,后面的点表示调用对象属性。如果不加括号,这个点会被JavaScript引擎解释成小数点,从而报错。
        
        // 只要能够让JavaScript引擎不混淆小数点和对象的点运算符,各种写法都能用。除了为10加上括号,还可以在10后面加两个点,JavaScript会把第一个点理解成小数点(即10.0),把第二个点理解成调用对象属性,从而得到正确结果。
        10..toString(2) // "1010"
        
        // 其他方法还包括
        10 .toString(2) // "1010"
        10.0.toString(2) // "1010"
        
        // toFixed方法用于将一个数转为指定位数的小数,返回这个小数对应的字符串。
        (10).toFixed(2) // "10.00"
        10.005.toFixed(2) // "10.01"
        
        // toExponential方法的参数表示小数点后有效数字的位数,范围为0到20,超出这个范围,会抛出一个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方法的参数为有效数字的位数,范围是1到21,超出这个范围会抛出RangeError错误。
        (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)是当初被要求要像java才做出来的方式,实际上更受人喜欢的依然是var n = 1
        但是这样方式无法使用Number对象的方法怎么办,于是又有了下面的东西;
      • 基本包装类型
        理论上基本类型是不能没有toString()之类的方法的,然而实际上却可以使用,
        这是因为每当地区一个基本类型值的时候,后台就会创建一个对应的基本包装类型的对象,从而让我们能够调用一些方法来操作这些数据,如下:
        var n = 1  // 1
        var s = n.toString()  // '1'
        // 后台自动操作
        var temp = new Number(n)  // 创建一个 Number 类型的实例
        temp.toString()  // 调用指定方法
        // 然后将temp.toString()的值作为n.toString()的值
        // 最后销毁temp,释放空间
        // 所以这是一种临时的转换,基本类型实际上并没有属性,
        
        也因此,var n = new Number(1)这种方式基本不再被大家所使用
      • 思考题
        var n = 1
        n.xxx = 2
        // 问:是否会报错?
        // NO!
        n.xxx  = 2 // 2
        n.xxx  // undefined
        

        解析:n.xxx = 2这段代码执行时新建了一个临时变量temp以及属性xxx储存值2,所以不会报错,
        但是执行 n.xxx 的时候浏览器显示的却是 undefined,这是因为 temp 是临时创建出来了,使用后会立即销毁,执行 n.xxx 的时候上一句代码创建的临时temp已经被销毁了,这时候又是一个新的temp,它并没有xxx这个属性以及值


      • String()和Boolean()也是同理
      • 阮一峰
      • JavaScript高级程序设计第五章-5.6-基本包装类型

    2. String()

    • MDN
    • MDN学习教程
    • 阮一峰
    • var s = 'abc'
      var s2 = new String(s)
      
      // charAt方法返回指定位置的字符,参数是从0开始编号的位置。
      s.charAt(1) // "b"
      s.charAt(s.length - 1) // "c"
      // 这个方法完全可以用数组下标替代。
      'abc'.charAt(1) // "b"
      'abc'[1] // "b"
      // 如果参数为负数,或大于等于字符串的长度,charAt返回空字符串。
      'abc'.charAt(-1) // ""
      'abc'.charAt(3) // ""
      
      // charCodeAt方法返回给定位置字符的Unicode码点(十进制表示),相当于String.fromCharCode()的逆操作。
      'abc'.charCodeAt(1) // 98
      // 如果没有任何参数,charCodeAt返回首字符的Unicode码点。
      'abc'.charCodeAt() // 97
      // 如何返回 16 进制表示的Unicode码点
      'abc'.charCodeAt(0).toString(16)
      
      // trim方法用于去除字符串两端的空格,返回一个新字符串,不改变原字符串。
      '  hello world  '.trim()  // "hello world"
      // 该方法去除的不仅是空格,还包括制表符(\t、\v)、换行符(\n)和回车符(\r)。
      '\r\nabc \t'.trim()  // 'abc'
      
      // concat方法用于连接两个字符串,返回一个新字符串,不改变原字符串。
      var s1 = 'abc';
      var s2 = 'def';
      s1.concat(s2) // "abcdef"
      s1  // "abc"
      s2  // "def"
      // 该方法可以接受多个参数。
      'a'.concat('b', 'c') // "abc"
      
      // slice方法用于从原字符串取出子字符串并返回,不改变原字符串。
      // 它的第一个参数是子字符串的开始位置,第二个参数是子字符串的结束位置(不含该位置)。
      'JavaScript'.slice(0, 4) // "Java"
      // 如果省略第二个参数,则表示子字符串一直到原字符串结束。
      'JavaScript'.slice(4) // "Script"
      // 如果参数是负值,表示从结尾开始倒数计算的位置,即该负值加上字符串长度。
      'JavaScript'.slice(-6) // "Script"
      'JavaScript'.slice(0, -6) // "Java"
      'JavaScript'.slice(-2, -1) // "p"
      // 如果第一个参数大于第二个参数,slice方法返回一个空字符串。
      'JavaScript'.slice(2, 1) // ""
      
      
    • String()有很多api,这里只写了几个常用的,更多详见上面两个链接

    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,因为 f2 并不是 false,因为它是一个对象,而对象是 true     
      // 别忘记js中只有 NAN、null、undefined、''、0是false,而对象和其它的都是true
      

    4. Object()

    • MDN
    • 阮一峰
    • var o = {}
      var o2 = new Object()
      // 这两种写法的结果没有任何区别,因为 对象 本身是复杂类型,但是
      o === o2  // false
      // 这是因为它们虽然都创建一个空对象,但是地址并不一样,是两个地址不同拥有自己空间的空对象
      
  • 公共属性(原型)

    var n = new Numer(1)
    var s = new String('a')
    var b = new Boolean(true)
    var o = new Object()
    
    // 上面4个不同的对象都有`toString()、valueOf()`属性,可是如果每个对象都创建2个属性会很浪费内存,
    // 所以,共用就好了
    

    那么怎么访问公共属性呢?每个对象的toString储存公共属性的toString的地址?不

    • proto
      js通过隐藏属性__proto__属性来访问公共属性,它指向了那些所有对象共有的属性


      步骤:
      1. 首先查看自身是否是对象,如果不是就包装对象
      2. 如果是对象就查看自身的 key 有没有 toString,有的话就直接调用
      3. 如果没有的话就通过__proto__查看你的共用属性看有没有,有的话就将你自身对应的值打印出来
        例子:
      var o1 = {name: 'zero'}
      o1.toString()  // [object Object]
      // 依照步骤来,o1是对象,o1没有toString,查看共有属性,有toString,打印o1对应的值
      // 不仅仅是o1,创建更多的对象也是一样,所有的对象都有隐藏属性`__proto__`,指向对应的共有属性
      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__指向对象共有属性
    • 除了Number以外,类似的还有String、Boolean(目前所学的)


    • 原型链
      • 对象的属性和方法,有可能定义在自身,也有可能定义在它的原型对象。由于原型本身也是对象,又有自己的原型,所以形成了一条原型链(prototype chain),就像我们上面画的图一样,

      • 如果一层层地上溯,所有对象的原型最终都可以上溯到Object.prototype,即Object构造函数的prototype属性。Object.prototype 就是 Object对象的共有属性,相对的,Number.prototype就是Number对象的共有属性,而Number.prototype的proto又指向Object.prototype,也就是它的共有属性,String和Boolean也是如此




        看这张图,结合前面所学的数据结构,是不是很有意思,
        根节点是Object.prototype,三个子节点分别是String.prototype、Number.prototype、Boolean.prototype,
        当你执行var str = new String('a')时,浏览器就会在堆中创建一个hash,str保存这个hash的地址,
        这个hash也就是String对象中除了你定义的属性外还有隐藏属性proto指向String.prototype,String.prototype又指向Object.prototype,这就完成了String API的所有绑定,
        Number和Boolean也是一样

      • “原型链”的作用是,读取对象的某个属性时,JavaScript 引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。

      • 如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overriding)。

      • 需要注意的是,一级级向上,在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。

      • prototype与proto


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



        proto 是对象的属性,prototype 是函数的属性
        它们储存的地址相同,指向的其实是同一个对象

        // 一些烧脑的东西
        
        var obj1 = 函数.prototype
        obj1.__proto__  === Object.prototype  // 等于下面
        函数.prototype.__proto__ === Object.prototype
        
        var obj2 = 函数
        obj2.__proto__ === Function.prototype  // 也就是
        函数.__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__ === 函数.prototype
        函数.__proto__ === Function.prototype
        参考

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

      • Object.getPrototypeOf(Object.prototype) // null
        上面代码表示,Object.prototype对象的原型是null,由于null没有任何属性,所以原型链到此为止。
        Object.prototype 就是 Object对象的共有属性

      • 阮一峰

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容