js里一切皆是对象。
prototype
首先,prototype是一个属性,是属于函数的一个属性。
JavaScript中任意对象都有一个内置属性[[prototype]] es5之前是没有一个标准的方法来访问这个属性的,但是大多数的浏览器都支持通过__proto__来访问 也就是说,我们是用__proto__这个属性来访问prototype这个属性的
__proto__与prototype的关系:
对象的__proto__ 指向其构造函数的prototype对象
方法这个特殊的对象,除了和其他对象一样有上述_proto_属性之外, 还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象, (我们把这个对象叫做原型对象)。 原型对象有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。 Note:通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性
比如:
function Person(){}
Person.prototype.a=1
Object.prototype.toString.call(Person.prototype)
//"[object Object]"
请确认,是多数的函数都有prototype属性。 比如对象字面量是没有这个属性的。如果你强行的给对象字面量添加该属性的话是会报错的。 比如
var a ={x:1}
a.prototype.y=2//Error
Uncaught TypeError: Cannot set property 'y' of undefined
关于__proto__的指向 所有的对象都有__proto__属性(null 除外)。 对象的__proto__指向,构造这个对象的构造函数的prototype。
通过对象直接量创建的对象使用Object.prototype作为他们的原型对象。
var a = {}
a.__proto__== Object.prototype //true
通过new创建的对象使用构造函数的prototype属性作为他们的原型。
function ClassA (name){
this.name = name
}
ClassA.prototype.age = '20'
var a =new ClassA('a')
a.name
a.age
a.__proto__==ClassA.prototype
通过Object.create() 创建的对象使用第一个参数作为他们的原型
Object.create(proto, [propertiesObject])
该方法会使用指定的原型对象及其属性去创建一个新的对象。
proto 新创建对象的原型对象。
propertiesObject 属性对应Object.defineProperties()的第二个参数。
可以用来进行继承
如下
var a = {a:1,b:2}
var d = Object.create(a)
d=>{}
d.a=1
d.__proto__ == a//true
d的原型就指向第一个参数,a
什么是__proto__
对象具有属性__proto__,别名为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。 也就是js的继承,比如:
var arr = [1,2,3,4]
arr.join('')//1234
arr是没有join这个方法的,而之所以我们能够使用,是因为其构造函数Array.prototype中存在这个函数。
你可以打印看一下,所有的数组方法,都在里边。
而Array.prototype==arr.__proto__
js会查看arr中是否有join方法,然后发现,没有这个方法,而后顺着隐式的原型__proto__网上找,找到Array.prototype,发现找到了join方法,所以直接拿来使用,所以,即使。arr没有join方法,却依旧可以使用这个方法。
再比如字面量对象
var a = {x:1}
对象a的隐式原型也就是属性__proto__指向的是构造对象a的构造函数的原型。
a的构造对象就是Object()
那么a.__proto__ 指向的也就是Object.prototype
所以 a.__proto__==Object.prototype//true
再比如new对象
var a = new Object()
a.__proto__ == Object.prototype//true
其实,a= {}是一个语法糖。 当你写a = {}的时候,js内部其实是做了一层操作,a = new Object()的。
函数的原型
function a (){
console.log("我tmd的真是够了")
}
a.__proto__ == Function.property//true
其中,Function(){}是所有函数的构造函数。
所以下边的是成立的。
a.__proto__.__proto__==Object.prototype
等价于
a.__proto__ == Function.prototype
Function.prototype.__proto__ == Object.prototype
所以说。所有对象的 __proto__属性都指向了这个对象的构造函数的prototype属性。
例子
对象的__proto__属性指向构造该对象的构造函数的prototype
比如
{}.__proto__指向 Object.prototype
function func(){}
func.__proto__ 指向Function.prototype
而所有的函数的构造函数都是 Function函数
Foo() Object() Function()都是由Function函数构造的。
所以他们的 __proto__都指向了Function.prototype
我们前面说了,所有的对象最后都指向了Object,但是,现在我们发现
Object.__proto__==Function.prototype。//true
更奇怪的是
Function.__proto__== Function.prototype //true
而且
Function.prototype.__proto__ == Object.prototype//true
理解:
所有的函数,比如自定义的Foo(),或者是构造函数Object()都是由Function函数构建的,包括Function函数本身都是有
Function函数构建的(听着有点别扭)。
所以说,Object.__proto__==Function.prototype
Function.__proto__==Function.prototype
而Function.prototype是一个对象,类似于{}的一个对象,
而{}这样的对象是由Object构造函数构建的。
所以{}.__proto__==Object.prototype是没错的。
同样的。Function.prototype.__proto__==Object.prototype也是没错的
如上 到最后 所有的原型都指向了Object.prototype
而Object.prototype.__proto__指向了null
至此就到了原型链的顶端。
用法
Object.prototype可以给所有的Object类型的对象添加属性
比如
Object.prototype.a="123"
var obj = {x:1}
obj.a=>"123"
function func (){}
func.a=>"123"//虽然这样好像没啥卵用
var arr = new Array()
arr.a=>"IM BOSS"
var str = new String()
str.a =>"IM BOSS"
最后说了那么多,好像是忘记了constructor属性了。 所谓的constructor就是对象原型的一个属性。 理一理概念。 对象的__proto__属性指向,该对象的构造函数的prototype属性。
那么构造函数的prototype对象也拥有一个属性叫做constructor,这个属性,又指回到构造函数,
具体的是没啥卵用,就是一个标志,标志这个对象是哪来的 比如下边的几个;例子。
我们写了一个构造函数,用来构造对象。
function Foo(name,age){
this.name=name
this.age=age
this.hello=function(){
console.log('你好,我叫'+this.name+",今年"+this.age +"岁。")
}
}
Foo.prototype = {name:'12312313'}
var foo = new Foo('小忙',12)
Object.prototype.toString.call(foo)//"[object Object]"
那么此时。foo看着像是一个函数,其实他是一个对象,类似于{}的一个对象。
foo.__proto__ == Foo.prototype//true
Foo.prototype.constructor == Foo//true
这里。constructor属性就是一个标志的作用
foo.__proto__.constructor==Foo//表面,foo这个对象是由Foo这个构造函数构造的
重要的是他是没有prototype属性的
foo.property==undefined
第二个,我们来写个普通的函数 请记得函数都是由Function() 生成的
function foo(){}
foo是一个函数,按照上述,每一个函数在创建之后都会拥有一个名为prototype的属性的。
foo.prototype是一个对象,对象包含了一个constructor属性
而,foo函数的隐式原型如下所示,再说一下,函数的构造函数都是Function
foo.__proto__== Function.prototype
foo.__proto__.constructor==Function
第三个,我们来写一个普通的对象
var obj = {}
obj.__proto__ ==Object.prototype//true
obj.__proto__.constructor == Object//true
这样的对象是没有prototype属性的