JS里的对象和原型

2019-02-14  本文已影响18人  酒极子

本博客主要讲以下几部分

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

全局对象window

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

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

这些全局变量分为两种:

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 里找到详细的资料。

全局函数

先看以下代码

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

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

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

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

接下来看这一题

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
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里的对象到底是什么了

上一篇下一篇

猜你喜欢

热点阅读