您的位置:首页 > 移动开发 > Objective-C

Js中Prototype、__proto__、Constructor、Object、Function关系介绍

2017-03-14 00:42 766 查看
Function、Object、Prototype、__proto__内存关系图



        上面的内存图跟堆栈结构可以参照文章Javascript_01_理解内存分配

        堆区图说明:


 
        Function.prototype函数对象图内部表示prototype属性的红色虚框,只是为了说明这个属性不存在。

        通过上图Function、Object、Prototype关系图中,可以得出一下几点:

所有对象所有对象,包括函数对象的原型链最终都指向了Object.prototype,而Object.prototype.__proto__===null,原型链至此结束。
Animal.prototype是一个普通对象。
Object是一个函数对象,也是Function构造的,Object.prototype是一个普通对象。
Object.prototype.__type__指向null。
Function.prototype是一个函数对象,前面说函数对象都有一个显示的prototype属性,但是Function.prototype却没有prototype属性,即Function.prototype.prototype===undefined,所有Function.prototype函数对象是一个特例,没有prototype属性。
Object虽是Function构造的一个函数对象,但是Object.prototype没有指向Function.prototype,即Object.prototype!==Function.prototype。

二    Prototype跟Constructor关系介绍
         在 JavaScript 中,每个函数对象都有名为“prototype”的属性(上面提到过Function.prototype函数对象是个例外,没有prototype属性),用于引用原型对象。此原型对象又有名为“constructor”的属性,它反过来引用函数本身。这是一种循环引用(i.e. Animal.prototype.constructor===Animal)。

        通过以下例子跟内存效果图来分析Prototype、constructor间的关系。

    console.log('**************constructor****************'); 

    console.log('anim.constructor===Animal:'+(anim.constructor===Animal))    ;    //true
    console.log('Animal===Animal.prototype.constructor:'+(Animal===Animal.prototype.constructor))    ;    //true
    console.log('Animal.constructor===Function.prototype.constructor:'+(Animal.constructor===Function.prototype.constructor));   //true
    console.log('Function.prototype.constructor===Function:'+(Function.prototype.constructor===Function));    //true
    console.log('Function.constructor===Function.prototype.constructor:'+(Function.constructor===Function.prototype.constructor));    //true

    console.log('Object.prototype.constructor===Object:'+(Object.prototype.constructor===Object));    //true
    console.log('Object.constructor====Function:'+(Object.constructor===Function));    //true

 prototype、constructor内存关系图(在Function、Object、Prototype关系图上加入constructor元素):



        上图中,红色箭头表示函数对象的原型的constructor所指向的对象。

注意Object.constructor===Function;本身Object就是Function函数构造出来的        
如何查找一个对象的constructor,就是在该对象的原型链上寻找碰到的第一个constructor属性所指向的对象。

参考:
http://www.cnblogs.com/fool/category/264215.html (javascript原理介绍)

http://www.libuchao.com/2012/05/14/prototypes-in-javascript/ (JavaScript 的原型对象 Prototype)
http://rockyuse.iteye.com/blog/1426510 (理解js中的原型链,prototype与__proto__的关系)

我们接着看代码:

[javascript] view
plain copy

function Person(name)  

{  

   this.name=name;  

   this.showMe=function()  

        {  

           alert(this.name);  

        }  

};  

  

Person.prototype.from=function()  

{  

  alert('I come from prototype.');  

}  

  

var one=new Person('js');  

  

one.showMe();//js,这个结果没有什么好奇怪的  

one.from();//I come from prototype.,这个结果有一点奇怪吧  

 

要解释这个结果就要仔细研究一下new这个操作符了.var one=new Person('js');这个语句执行的过程可以分成下面的语句:

[javascript] view
plain copy

var one={};  

Person.call(one,'js');  

按照《悟透javascript》书中说的,new形式创建对象的过程实际上可以分为三步:

第一步是建立一个新对象(叫A吧);

第二步将该对象(A)内置的原型对象设置为构造函数(就是Person)prototype 属性引用的那个原型对象;

第三步就是将该对象(A)作为this 参数调用构造函数(就是Person),完成成员设置等初始化工作。

其中第二步中出现了一个新名词就是内置的原型对象,注意这个新名词跟prototype对象不是一回事,为了区别我叫它inobj,inobj就指向了函数Person的prototype对象。在person的prototype对象中出现的任何属性或者函数都可以在one对象中直接使用,这个就是javascript中的原型继承了。

又头晕了,上图吧!inobj就是__proto__ 即,one.__proto__ == Person.prototype



这样one对象通过内置的原型对象inobj就可以直接访问Person的prototype对象中的任何属性与方法了。这也就解释了上面的代码中为什么one可以访问form函数了。因为prototype对象中有一个constructor属性,那么one也可以直接访问constructor属性。

代码:

 

 

 

 

 

 

[javascript] view
plain copy

function Person(name)  

{  

   this.name=name;  

   this.showMe=function()  

        {  

           alert(this.name);  

        }  

};  

  

Person.prototype.from=function()  

{  

  alert('I come from prototype.');  

}  

  

var one=new Person('js');  

  

one.showMe();//js,这个结果没有什么好奇怪的  

one.from();//I come from prototype.,这个结果有一点奇怪吧  

alert(one.constructor);//function Person(name) {...}  

alert(Person.prototype.constructor);//function Person(name) {...}  

 接着看继承是如何实现的。

[javascript] view
plain copy

function Person(name)  

{  

   this.name=name;  

   this.showMe=function()  

        {  

           alert(this.name);  

        }  

};  

  

Person.prototype.from=function()  

{  

  alert('I come from prototype.');  

}  

  

function SubPerson()  

{  

}  

SubPerson.prototype=new Person();  

  

var subOne=new SubPerson();  

subOne.from();//I come from prototype.  

alert(subOne.constructor);//function Person(name) {...};  

alert(SubPerson.prototype.constructor);//function Person(name) {...};  

继承的实现很简单,只需要把子类的prototype设置为父类的一个对象即可。注意这里说的可是对象哦!

 那么通过prototype属性实现继承的原理是什么呢?还是先看图形说明,然后编写代码进行验证。



 

 
  用图像直观表示如下:



                                                                          图 1.3
到此说明了a,b两点是正确的。

同事上面的也可以论证一下观点(该观点摘自JavaScript权威指南):
1)  同一个类的所有实例都从同一个原型对象上继承属性
2)  当且仅当两个对象继承自同一个原型对象时,他们才是属于同一个类的实例
特别说明:只有构造函数才有prototype属性,而构造函数的实例是没有该属性的,也就是说console.log(a1.prototype)输出的是undefined。在javascript中,每个函数都自动有一个prototype属性,而不是每一个对象拥有prototype属性
  原型属性与实例对象的创建与否没有关系,它在对象创建之前就已经存在

  直观表示如下图:
   


                                                                      图 1.5

注意:新定义Prototype对象的话,该Prototype对象原有的constructor属性会丢失,该Prototype此时所指的对象(即{getName:function(){return this.name}}对象)的constructor就是Object,事实上{getName:function()}就是一个Object对象。相信如果A.prototype={getName:function(){returnthis.name}}换成这样写的话,理解起来会方便写:
Var obj = {getName:function(){}}
A.prototype = obj;
//或者这样写:
Var obj = new Object();
Obj.getName = function(){
};
A.prototype = obj;
此时用图形表示a1,a2,prototype对象的关系如下:



通过这个图可以很直观的看出:
a1.constructor ===  A//=>false
a1.constructor === Object//=>true
A.prototype.constructor === Object

.修改这个问题的办法就行给重定义的Prototype对象显式的添加一个constructor属性,修改其constructor的指向:

 

/**
* Created by duqiong on 17/3/13.
*/
function A(name){
this.name = name;
this.show=function () {//只是实例方法,不实例化无法调用
console.log('inner-'+this.name+'   inner show');
// A.show();
}
}
A.shows=function () {
console.log('static-'+this.name+'    static show');
}
var a2 = new A("aa2");
A.prototype.show1=function () {//只是在A的原型对象(实例)增加实例方法,不需要实例化不能调用
console.log('prototype show');
}
A.alarms=function () {
console.log('sdfsdfs');
this.alarm=function () {//只是修改了类方法,类方法不需要实例化
console.log('inner dynamic alarm');
}
//this.alarm();
}
var a1 = new A("aa1");
// console.log(a1);
console.log(a2);
console.log(a1.constructor);
console.log(a2.constructor);
console.log(a2.constructor.constructor);
console.log(A.prototype);
console.log(a1.__proto__);
console.log(A.constructor);
console.log(a1.prototype);
//
A.shows();
a1.__proto__.constructor.shows();//通过实例调用类静态方法
a1.constructor.shows();//通过实例调用类静态方法
a1.show();

A.alarms();

A.alarms();
console.log(a1.__proto__===A.prototype);console.log(a1.constructor===A);console.log(A.prototype);a1.show1();
////print//////

A { name: 'aa2', show: [Function] }

{ [Function: A] shows: [Function], alarms: [Function] }

{ [Function: A] shows: [Function], alarms: [Function] }

[Function: Function]

A { show1: [Function] }

A { show1: [Function] }

[Function: Function]

undefined

static-A    static show

static-A    static show

static-A    static show

inner-aa1   inner show

sdfsdfs

inner dynamic alarm

true

true

A { show1: [Function] }

prototype show
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  prototype