大家肯定都知道,JavaScript其实和Java并没有什么关系,当时推出JS时,只是为了趁一下当时如日中天Java大哥的热度。JS中的语法和数据结构太简单了,以至于很长一段时间内,JS程序员都被称为脚本员。而被如此嘲讽的原因,是因为当时的JS不存在”类”的这个概念的,更不用说”模组”这种东西了。
一等公民
在JS世界中,人们常说,函数是一等公民(first-class object),但为什么要这么说呢?
举个例子:
1 | > var a = 1 |
从上面的列子可以看出,
1 | > var b = new Number(1) |
当然,由于
JS的原生值类型包含以下几种
- number
- string
- boolean
- symbol (ES6新增)
- null
- undefined
以上的值类型中,除开
再举个例子:
1 | > var a = {} |
上面的例子显示出,函数直接参与了对象的构建工作(constructor)。虽然JS并没有实际“类”的概念,但还是可以将之称为构造函数。
除了参与构建JS世界其他部分的工作外,函数自己也是这个世界的一部分。它无处不在,除了作为对象被引用,还经常作为参数被传递,偶尔还客串返回值。它的父类是Object,Object的父类是它。
1 | > Function.__proto__ |
_proto_ 和 prototype
讨论JS对象,绕不开的就是 _proto 和 prototype,除了 undefined 和 null__ 以外,JS中所有对象都含有 _proto__ 属性,那么这个属性是干嘛的?
让我们先写一个函数:
1 | function Person(name) { console.log(`I'm ${name}`) } |
单独执行它:
1 | > Person('EvinK') |
执行该函数时,输出了一句话,返回了一个 undefined
加上
1 | function Person(name) { |
发现了吗?new关键字调用函数时,该函数返回了一个以它自身为原型的对象。同时,在执行Person函数的过程中,将挂载于Person作用域下的属性,也一同挂载到生成对象上(函数闭包)。
现在,让我们看下person的属性
1 | Person {name: "EvinK"} |
除了挂载到身上的name属性外,person的_proto__属性暴露了它的原型 —— Person函数,而我们亦可以沿着 _proto 属性一直深究下去,会发现,对象person 的原型是 Person函数, 对象person 原型的原型是 Object函数,而再往后面就是null了,也就意味着这条 原型链_ 终止了。
总结一下,对象中的 _proto_属性指向的是自身原型的 prototype属性, 并且依靠条链接层层递进,直到找到最终原型函数Object。