先举个简单的例子
var a = 0
a.data='data'//可以用a.data取值
a.__proto__.data1='data1'//可以用a.data1取值
a.__proto__.__proto__.data2='data2'//可以用a.data2取值
a.__proto__.__proto__.__proto__.data3='data3'//Cannot set property 'data3' of null
这就是传说中的原型链,访问对象的属性的时候如果对象的属性中有这个字段,则直接返回,如果对象中没有这个字段,则从对象的__proto__中寻找,如果__proto__中没有,就从__proto__.__proto__中寻找。直到__proto__.......__proto__为null。
接下来一层一层剖析,
1.
var a=0
打印出来a就是个0,
接下来打印a.__proto__
Number {0, data1: "data1", constructor: ƒ, toExponential: ƒ, toFixed: ƒ, …}
知识点:一个对象的__proto__就是这个对象的构造函数的prototype,所有对象都有__proto__和constructor属性,所有函数都有prototype属性,函数也是对象,所以函数有这三个属性
也就是说a的构造函数是Number,
再打印typeof Number
"function"
也就是说,Number其实是个函数,所以对a而言,Number就是构造函数了,对,就是个函数,跟我们写的function一样,只是function fun(){} var f=new fun(); typeof f的结果是object
2.
既然透过表象看到了本质,那就再来看看function
function fun(){}
var f = new fun();
typeof f
输出
"object"
f也就是new出来的一个函数对象
接下来加几个属性
function fun(){
this.a = 'aaaa'
}
fun.__proto__.b = 'bbbb'
fun.prototype.c = 'cccc'
var f = new fun()
f.d = 'dddd'
f.__proto__.e = 'eeee'
//f是对象,所以没有prototype,所以不能f.prototype.x='xxxx'
//这里不使用this.name='abc',因为function有name属性,以免造成歧义
命令及其输出:
f.e
"eeee"
f.d
"dddd"
f.c
"cccc"
f.b
undefined
f.a
"aaaa"
f.e是f.__proto__的属性,不是f的属性,f的__proto__也就是f的构造函数的prototype,跟fun.prototype.c一个级别的,证明:
fun.prototype
{c: "cccc", e: "eeee", constructor: ƒ}
f.d是给f添加属性,也就是f自己的内容,不用证明,但还是打印一下:
f
fun {a: "aaaa", d: "dddd"}
c就不用说了,只能再次证明f.__proto__===fun.prototype
fun.__proto__.b是fun.__proto__的属性不是f的原型链上的,因为原型链只是__proto__属性的链表,fun自己本身就是一个函数,
fun instanceof Object
true
他有自己的__proto__,没有参与到f的原型链上。
小扩展:
var g = new fun()
g.a
"aaaa"
f.__proto__===g.__proto__
true
这个例子更说明了一个对象的多个实列的__proto__源自同一个prototype
f是个对象的描述可能不够准确,f应该是一个对象的实例
3.
function都看了,再来看看Function
书接上例,主要讲fun的实例的属性,以及自己的__proto__和prototype,那么
fun.__proto__.b呢
Function.b
"bbbb"
知识点:函数的构造函数是Funciton,Function的构造函数是Function自身
Function.constructor===Function
true
如果fun.g='gggggg',该怎么获取呢??
只能用fun.g获取,因为fun的实例只是获取了fun的prototype,而fun是一个Function实列,fun的构造函数要想获取得用fun.__proto__也就是fun独有的属性,
f.a能获取到a是因为this.a中this是实列对象,也就是new的时候的那个对象也就是f,而g不是this的,是fun的。
4.
已经知道了__proto__的作用:获取属性值,充当原型链,对象的__proto__就是这个对象的构造函数的prototype
接下来看看prototype
函数自己可以有__proto__,他的实例可以继承这个__proto__,他的实列的__proto__就是这个函数的prototype,也就是说prototype的作用就是用来给他的实列的__proto__赋值,没错就只做这个事情了。
虽然说起来很简单,但是要理解prototype中存放了什么,存放了这个原型的所有属性,因为实例的__proto__的属性都是从这个prototype中来的,所以prototype也算是一个原型的所有实例的容器,所有实例只会继承prototype的引用,这样就达到了一个属性的修改,在所有实例中生效,看起来是__proto__的作用,但是每个实例的__proto__都来自同一个prototype,才能实现这个效果
function fun(){
this.a = 'aaaa'
}
var f1 = new fun()
var f2 = new fun()
f1.b='bbb'
f1.__proto__.c='ccc'
f1
fun {a: "aaaa", b: "bbb"}
f2
fun {a: "aaaa"}
f2.c
"ccc"
f2能取到f1设置的c属性,就是这个作用
fun.prototype
{c: "ccc", constructor: ƒ}
c: "ccc"
constructor: ƒ fun()
__proto__: Object
不给protoype赋值的话,prototype只有一个constructor函数,和所有对象都有的__proto__属性。
5.
constructor就是构造函数
f1.constructor===fun
true
f1.constructor.__proto__===Object.__proto__
true
f1.constructor===Object
false
f1.constructor.__proto__==Function.__proto__
true
f1.constructor.__proto__==Function
false
f1.constructor.__proto__==Array.__proto__
true
Function.constructor===Function
true
就不赘述了,constructor就只是函数,Function的构造函数是Function本身
6.小扩展:
class c extends fun{}
c
输出:class c extends fun{}
class可以继承自function
class就是个特殊的function
function还有些知识点:call、apply、bind。闭包。
闭包比较有趣,可以研究研究