原型

160 阅读5分钟

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属性的