现在的位置: 首页 > web前端 > 正文

JavaScript原型继承机制

2018年10月28日 web前端 ⁄ 共 5078字 ⁄ 字号 评论关闭
文章目录
JavaScript原型继承机制

        JavaScript并非一个纯粹的面向的对象的语言,也没有一个实际意义上的继承机制。语言的设计者最初并未想实现继承机制,但是后来还是实现了一个类似的机制——原型继承机制但实际上,这并非实际的继承,我们来一一揭开JavaScript的伪继承机制

一、typeof 和 instanceof

       在JavaScript中,typeof是测试对象的类型,只会测试出对象属于哪种内置类型,无法测试自定义类型。也就是所有自定义类型都会返回object。

       而obj instanceof sometype(obj 指对象,sometype指的是类型),是测试obj的原型链中是否有sometype类型。所以通过错误的改变prototype的值会使得instanceof得出的结构不合理。

1、typeof

<script>
var num = 10;
document.write("typeof num:"+typeof num+"<br/>");
var onum = Number(10);
document.write("typeof onum:"+typeof onum+"<br/>");

var str = "1010";
document.write("typeof str:"+typeof str+"<br/>");
var ostr = String("1010");
document.write("typeof ostr:"+typeof ostr+"<br/>");

var bol = true;
document.write("typeof bol:"+typeof bol+"<br/>");
var obol = true;
document.write("typeof obol:"+typeof obol+"<br/>");

var dat = new Date();
document.write("typeof dat:"+typeof dat+"<br/>");

var func = new Function('x','y',"return x+y;");
document.write("typeof func:"+typeof func+"<br/>");

var myconstructor = function Person(){};
document.write("typeof myconstructor:"+typeof myconstructor+"<br/>");

var myobj = new myconstructor();
document.write("typeof myobj:"+typeof myobj+"<br/>");
</script>

结果:

typeof num:number
typeof onum:number
typeof str:string
typeof ostr:string
typeof bol:boolean
typeof obol:boolean
typeof dat:object
typeof func:function
typeof myconstructor:function
typeof myobj:object

这说明元构造器的类型为:function
内建的普通构造器类型为:function
自定义普通构造器类型为:function
所有内置对象类型为:内置类型
所有自定义普通对象:object

2、instanceof

实际就是测试实例是否有继承基类的原型链,如obj  instanceof Type,若obj的原型链中Type则返回true,否则返回false

//案例一
var Person = function(){};
var obj = new Person();
document.write((obj instanceof Person) +"<br/>");
document.write((obj instanceof Object) +"<br/>");
document.write(obj.__proto__ +"<br/>");
document.write(Person.constructor+"<br/>");
document.write(obj.constructor+"<br/>");
document.write((obj.constructor === Person)+"<br/>");

结果:

true
true
[object Object]
function Function() { [native code]}
function (){}
true

//案例二
var other = function(){};
Person.prototype = new other();
document.write((obj instanceof Person) +"<br/>");
document.write((obj instanceof Object) +"<br/>");
document.write((obj instanceof other) +"<br/>");
document.write(obj.__proto__ +"<br/>");
document.write(obj.constructor+"<br/>");

结果:

false
true
false
[object Object]
function (){}

//案例三
obj.__proto__ = new other();
document.write((obj instanceof Person) +"<br/>");
document.write((obj instanceof Object) +"<br/>");
document.write((obj instanceof other) +"<br/>");
document.write(obj.__proto__ +"<br/>");

结果:

false
true
true
[object Object]

下面我们就来具体分析这三个案例:

(1)案例一

                                                                 var Person = function(){};

这句具体发生了什么呢?我们用下面的伪代码来解释一下:生成了一个函数对象Person

{
       this.prototype = {constructor:this};      //{}表示一个Object构造的空对象         
       var prototype = Function.prototype;       //内部{Prototype}属性,不能改变
       this.__proto__ = prototype;               //内部属性的外部访问方式,
       this.constructor = this;                  // 默认的,也是合理的值
}

                                                                                           var obj = new Person();

这句发生了什么呢?我们也用伪代码来解释一下:生成普通对象obj

{
      var prototype = Person.prototype;
      this.__proto__ = prototype;
      this.constructor = Person;
}

按此来说,在案例一中:

//function类型
Person.__proto__=== Function.prototype;       
//object类型,  默认情况下每个构造器内部都有一个Object的实例对象,供所有子类共享,这就是所有对象都默认继承object的实例的原因
Person.prototype ===  obj.__proto__  ;
//验证每个自定义类型都默认继承自一个Object实例object           
Person.prototype.__proto__ = Object.prototype;
//每个对象的构造器为构造它的函数对象
Person.constructor === Function;
Function.constructor === Function;    //说明Function由自己构造,自举性
obj.constructor === Person;
//从中可以看出prototype告诉构造器,你构造的对象应该继承谁
//__proto__可以告诉我们该对象继承自谁。

其次我们可以看出:

//Function 的自举性
Function.prototype === Function.prototype;
Function.__proto__ === Function.prototype;
Function.constructor === Function;
//Object由Function构造
Object.prototype === Object.prototype;
Object.__proto__ === Function.prototype;
Object.constructor === Function;
Function.prototype.__proto__ === Object.prototype;  //说明Object.prototype是万物之源 

而obj对象呢,也有着这些特性,不过它是普通对象,没有公开属性prototype:

//普通对象特性
obj.__proto__  === Person.prototype;
obj.constructor === Person;

我们再来看看Object.prototype:

//元对象
Object.prototype === Object.prototype;        //对象的祖宗,根
Object.prototype.__proto__ === null;          //祖先没有祖先,单位了系统完备,其内部仍然有{Prototype}属性,置为null,合理。
Object.prototype.constructor === Object;      //祖先按理说是没有构造器的,但为了说明祖先仍然属于Object的实例,就这么做。

接着我们再看看Function.prototype:

//元构造器
Function.prototype === Function.prototype;            //由Function构造出来的对象的原型
Function.prototype.__proto__ === Object.prototype;    //对象Function.prototype的原型为Object.prototype
Function.prototype.constructor === Function;          
//对象Function.prototype是由构造器Function构造的,实际上并非如此,但是为了Function.prototype的类型是Function也就这么设计了。

二、prototype和{Prototype}(即__proto__)

        在Js中有两个顶级上司,或者说顶级公民:Function.prototypeObject.prototype

1.一切都是对象

        在Js中一切都是对象,而几乎所有对象都由构造器产生。不过有一个例外,所有对象的基础(元对象Object.prototype他不是由构造器产生,而是由Js引擎实现。它不同于java的Object——那是一个类,而Js中的Object.prototype仅仅是一个对象,它不能作为构造器。这来来讲就好比西方人类最初也只有两个人作为祖先——亚当夏娃但是在Js中只有一个没有构造功能的Object.prototype那么如何基于这个原型来构造子对象呢,这就需要下面讲到的元构造器——Function.prototype

2.Object.prototype不是由构造器产生

3.Function.prototype由自己构造,但是却是继承自Object.prototype

4.继承只是继承对象,所谓对象A继承自B,说明对象A维护者对象B的引用

5.函数对象中的__proto__才是指明该函数对象作为对象时继承自谁,或者说维护了哪个对象的引用

6.函数对象中有个特别的特性prototype,这是普通对象所不具有的,这是函数对象作为构造器时的特性,它指明了该构造器作为”伪类“时的内部数据结构,他是一个引用类型。由该构造器构造出来的对象都维护着prototype所引用的对象的引用

           事实上C/C++可以实现类似的功能,点击这里看看C/C++实现Js原型继承模式:C/C++实现Js原型继承机制

抱歉!评论已关闭.