网络上很多关于JS原型的理解,写了很多,我也看了很多,但总是云里雾里,很多文章一上来就说Object是一切对象的根对象,这句话非常误导人的思维,后来自己在控制台,自己分析出来了比较好理解的方式,下面我来详细屡屡关于js原型的正确理解方式。
主要是理解js中的对象,函数,函数对象,函数实例
首先我们来聊聊这四个概念
对象
对象是什么呢,对象就是使用json格式表示的代码块,用这种方式表示js中的对象如下:
{ "name":"runoob", "alexa":10000, "site":null }
JSON 对象使用在大括号 {...} 中书写。
对象可以包含多个 key/value(键/值)对。
key 必须是字符串,value 可以是合法的 JSON 数据类型(字符串, 数字, 对象, 数组, 布尔值或 null)。
key 和 value 中使用冒号 : 分割。
每个 key/value 对使用逗号 , 分割。
函数
函数就是function关键字定义的一段代码块,就是自己定义的看得到的那一块代码,称之为函数,js中内置了一些基础函数比如(Object,Date等等),其实质就是带有构造器constructor的对象,js中可以将一个带有构造器constructor的对象表示为为函数,函数是json对象的变体表现形式
(注意:永远不要忘记js中的对象就是json格式的代码块,函数是这个json格式对象的变体)
如下为Object函数的原型Object.prototype,也是一个json键值对对象:
{ {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} constructor: ƒ Object() hasOwnProperty: ƒ hasOwnProperty() isPrototypeOf: ƒ isPrototypeOf() propertyIsEnumerable: ƒ propertyIsEnumerable() toLocaleString: ƒ toLocaleString() toString: ƒ toString() valueOf: ƒ valueOf() __defineGetter__: ƒ __defineGetter__() __defineSetter__: ƒ __defineSetter__() __lookupGetter__: ƒ __lookupGetter__() __lookupSetter__: ƒ __lookupSetter__() __proto__: null get __proto__: ƒ __proto__() set __proto__: ƒ __proto__() }
函数有两种作用:一是执行特定功能的代码块,二是构造对象
函数对象
函数对象就是函数的原型,要与函数本身区分开来,比如Date函数的函数对象为Date.prototype,后面我在说特定函数对象的时候都会加上.prototype,因为这个函数原型才真正表述为函数对象
函数实例
函数实例就是通过函数构造器创造的对象,一个函数可以构造出多个不同的但相似的函数实例对象,例如:
function myFunction(a, b) { return a * b; } var x = myFunction (3, 3); var y = myFunction (4, 3); 从控制台可以分析出函数实例x,y是函数对象Number的子对象,其_proto_属性指向的是Number.prototype,而不是我们通常认为的x,y为myFunction.prototype的子对象 当然这里也不能绝对,因为函数实例的父对象是不确定的,如下实例 function myFunction2() { console.log('nihao'); } var z=myFunction2(); var m= new myFunction2();
VM360:3 nihao
undefined
z
undefined
函数实例z返回的日志为undefined
函数实例m返回的日志为myFunction2 {}
以上可知通过new关键字构造的新对象其父对象才指向其构造函数对象
对象与函数的基本认识
对象的_proto_属性指向的是当前对象的父对象
只有函数有constructor和prototype属性
函数中的prototype属性字面意思是原型,指的是当前函数的对象原型,函数只是这个对象原型的变体形式
按照我的理解是这样的,创造js这门语言的时候是定义这是一个面向对象的语言,所有首要任务就是指定对象的格式,就有json对象表示法,然后就是构造执行代码块的结构,即函数 表示法,再就是对象与函数的关联,想象js一切皆为对象,函数的定义本身也是在构造对象,即定义的函数可以表示为带有constructor的对象,这就是函数原型,然后通过函数定义法着手定义根对象就是Object.prototype以及其他的一些内置对象
关于Object与Object.prototype的理解
js中所有的对象继承自Object.prototype这个原型对象,这个原型对象用函数表示就是Object,所以很多文章都Object为根对象,这也没错,因为Object表示的就是根,只是这个根是以函数的形式表示出来,而这个函数的原型就是真正的根对象,即Object.prototype:{…}(这个里我省略了对象中的内容),这个Object.prototype派生了函数对象和普通对象(如Math,JSON等,因为这些对象中没有构造器,可自行在控制台查看),永远不要忘记Object这个函数是通过函数构造器构造出来的函数模样的一块代码,其本质是Object.prototype这个原型,这才是根对象。
Object是一个函数,其属性指针_proto_指向的是函数根对象ƒ () { [native code] },而函数根对象的_proto_则指向Object.prototype,应该有这样的关系:Object._proto_._proto_===Object.prototype;
不过js在_proto_属性后面就不让指针跟踪了,不过我们也可以通过变通的方式来查到,从这里可以看出来:
Object._proto_===Function.prototype //返回值都为ƒ () { [native code] };
Function.prototype.__proto__=== Object.prototype //返回值为true
Object.prototype._proto_则为null。
以上可以看出,JS中的一切对象都是Object.prototype的子对象,函数根对象ƒ () { [native code] }是Object.prototype的子对象,函数是函数根对象ƒ () { [native code] }的子对象,Object函数也不列外。(注意Function函数是函数根对象的显式函数声明,代表着函数根对象,函数根对象ƒ () { [native code] }是在js运行时已经定义好了的对象)
很多文章都说所有函数都派生自这个Function对象,准确的来说应该是所有函数对象派生自Function.prototype,而Function.prototype就是ƒ () { [native code] },那么问题来了,Object也是函数,那它也是派生自这个对象吗,是的,前面我已经说了,Object在js中写的时候是个函数不是根对象,而这个函数的原型Object.prototype才是真正的根对象,其形式为:这个在函数概念那里已经表述出来了,可以返回去巩固巩固。
关于JS Function函数理解
JS内置对象中,Function函数(注意我这里表述的是函数而不是函数对象,因为Function的函数对象准确来说应该为Function.prototype)较为特殊,这个理解起来就比较困难,因为Function.prototype===Function._proto_,很多人很疑惑为什么会等于,其实这里还缺少了一个重要的信息,那就是ƒ () { [native code] },这个才是根函数对象,这个根函数对象的父对象指向的是Object.prototype这个根对象,这是在js运行时中就已经定义好的,而Function.prototype这个函数对象原型恰好就是这个根函数对象ƒ () { [native code] },而这个Function._proto_这个属性指针恰好就指向了ƒ () { [native code] },这都是在js运行时中定义好了, Function这个函数的作用就是为了创建函数实例的另外一种方法,其父类对象还是Object.Prototype,只是显式定义函数的多一种选择。
好了,文章结束,希望对各位有所帮助!