美文网首页
JS里的对象和原型

JS里的对象和原型

作者: 酒极子 | 来源:发表于2019-02-14 18:29 被阅读18次

    本博客主要讲以下几部分

    全局对象 window
    全局函数
    公用属性是什么
    重要公式

    全局对象window

    ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对象(浏览器先存在的)

    window 就是一个哈希表,有很多属性。
    window 的属性就是全局变量

    这些全局变量分为两种:

    • 一种是 ECMAScript 规定的
    global.parseInt
    global.parseFloat
    global.Number
    global.String
    global.Boolean
    global.Object
    
    • 一种是浏览器自己加的属性(私有)
    history  //浏览器历史,也叫BOM
    window.alert  
    window.prompt
    window.comfirm
    window.console.log
    window.console.dir
    window.document  //有规范,叫DOM(W3C规定)
    window.document.createElement
    window.document.getElementById
    
    

    所有 API 都可以在 MDN 里找到详细的资料。

    全局函数

    • Number

    先看以下代码

    var n = 1
    var n1 = new Number(1) //创建一个 Number 对象
    

    那么问题来了,
    nn1 的区别是什么?
    这时画一个内存图就清楚了

    Number
    这样可以看出,nn1 的区别是内存上是不一样的
    那么Number(1)里写了什么呢?
    valueOf,toString...这些都是Number()函数内置的操作符,也就是说,如果包装成对象的话,n1就有更多便捷的操作给你用,而n就只有数字1
    • 临时转换

    这是为什么呢,因为JS发明时,JS之父的BOSS要求JS要长得像Java

    所以就有了Number()函数,但是实际上Number()基本没用,大家都喜欢直接用var n = 1,但是n.toString因为不是对象,所以不能直接转换

    这时,临时转换就出现了
    临时转换就是在想要调用ntoString操作时,创建一个临时对象,用这个对象的toString()方法去操作n,临时转换后就会把那个临时对象抹杀
    用内存图来理解是这样的:

    临时转换
    所以现在,就算我们只写var n = 1,之后也能使用复杂Number()的所有功能

    但是要注意的是,n本身是没有toString()函数的,只是利用来临时变量的方法,请看下面这题

    var n = 1
    n.xxx = 2
    那么,n.xxx的值是什么呢?
    
    临时转换2

    因为n只是将2存到临时变量的xxx里,所以n.xxx的值是undefined

    • String

    var s = 'asdfg'
    var s1 = new String(asdfg)
    

    和之前理解Number()一样,s之所以可以直接Number(s),是因为浏览器创建了一个临时对象,然后's'调用了这个对象的'Number()'方法,使用完后这个临时对象就被抹杀了

    这里要提一句的是,代码中的new如果不加,那就是用作转换用的。如果加了,就是生成对象。

    • Boolean

    接下来看这一题

    var f = false
    var f1 = new Boolean(false)
    if(f){console.log(1)}  //  打印1
    if(f1){console.log(2)}  //  打印2
    
    请问这题浏览器会打印出什么呢?
    

    我们画个内存图

    Boolean
    因为f=false,所以1是不会打印出来的
    因为f1实际上是一个对象,所以浏览器会打印出2
    • Object

    var o1 = {}
    var o2 = new Object()
    

    其实o1o2的方式根本没区别,只是他们的值内存地址不一样而已
    所以Object()基本没用

    • 小结

    看到这里,我们可以知道四个全局函数的作用和相应内存的改变了
    这些全局函数只是将值由基本类型变成了对象而已

    公用属性(原型)

    所有对象都有 toString 和 valueOf 属性,那么我们是否有必要给每个对象一个 toString 和 valueOf 呢?

    JS 的做法是把 toString 和 valueOf 放在一个对象里(暂且叫做公用属性组成的对象)
    然后让每一个对象的 __proto__ 存储这个公用属性组成的对象的地址

    • 这里可以看图来理解

    原型解释图

    在看这张图前,我们先考虑一下浏览器的垃圾回收机制,垃圾回收会回收没有被引用的对象。
    这些全局对象如果不被引用的话,就会被浏览器回收掉,如何避免这些全局属性被回收掉呢?

    浏览器在打开的时候,就会创建一个名为window的全局属性,这个全局属性包含了所有全局函数的地址值。
    这些地址又引用了该函数特有的公共属性(对象),每个函数特有的公共属性(对象)又用_prote_来储存Object对象的地址

    • 举个例子

    n.toString()
    

    流程是这样的
    1.浏览器先看n是不是对象,不是做临时转换。
    2.是的话就先去看看n对应的函数公共类型里找有没有toString()这个操作符
    3.如果没有,就进入_prote_对应的公共属性里找有没有toString()操作符
    4.有的话,就调用这个toString()

    这样的,形成的穿过多个节点的流程,就叫原型链

    • 内存图理解

    var o1 = new Number(8)
    var o2 = 8
    o1 === o2 // false
    o1.toString === o2.toString  //  true
    因为他们调用的方法是一样的
    
    内存图

    他们的数据类型是不一样的,但是他们调用的共同属性的方法(对象)是一样的

    重要公式

    由此,我们可以得出一个公式,结合原型解释图理解

    var 对象 = new 函数()
    对象.__proto__ === 对象的构造函数.prototype
    

    由这个公式,我们可以再推论

    var number = new Number()
    number.__proto__ = Number.prototype
    Number.__proto__ = Function.prototype // 因为 Number 是 Function 的实例
    
    var object = new Object()
    object.__proto__ = Object.prototype
    Object.__proto__ = Function.prototype // 因为 Object 是 Function 的实例
    
    var function = new Function()
    function.__proto__ = Function.prototype
    Function.__proto__ == Function.prototye // 因为 Function 是 Function 的实例!
    
    推论图

    这个公式如果你能读懂的话,你也就懂JS里的对象到底是什么了

    相关文章

      网友评论

          本文标题:JS里的对象和原型

          本文链接:https://www.haomeiwen.com/subject/someeqtx.html