js prototype 原型以及prototype原型链介绍
2017-01-14 02:00

prototype介绍

prototype我们通常叫做js的原型,你可以把prototype看作是一个指针对象,通过prototype可以获取一个对象的原型。每一个通过constructor构造函数创建的js对象都有一个内置的“__proto__”指向这个对象的prototype原型。

constructor介绍

construtor属性返回用来创建对象的构造函数的引用。

var mm = {};
mm.constructor === Object; // true
var mm = new Object;
mm.constructor === Object; //true
var mm= [];
mm.constructor === Array; // true
var mm = new Array;
mm.constructor === Array;//true
var mm= new Number(3);
mm.constructor === Number;// true
var mm=function(){}
mm.constructor===Function; //true

注意函数的constructor属性指向的是创建函数对象的构造函数Function,并不是函数的字面量字符串。

prototype详解

我们从主观上理解了prototype是原型的意思,但这不够透彻,我们通过代码示例来深入理解prototype。

我们先创建三个方法,

function first(){}

function second(){}

function three(){}

然后给second函数添加prototype属性

second.prototype={sdate:"2017-1-14"};
second.price="100";

var soo=new second();

console.log(soo.sdate);
//2017-1-14

console.log(soo.price);
//undefined;

我们通过new操作符创建了second的实例对象soo,soo对象可以获取second原型上的属性。但是soo获取不到second的静态属性。

first.prototype=second;

var foo=new first();

console.log(foo.price);
//100

console.log(foo.sdate);
//undefined;

我们将first函数的prototype指向了second,创建的first的实例foo可以获取second的静态属性,但foo获取不到second原型上的属性。

three.prototype=new second;

var too=new three();

console.log(too.price);
//undefined

console.log(too.sdate);
//2017-1-14

我们将three的prototype指向second的实例new second上,创建的three的实例too可以获取second原型上的属性,但是too获取不到second的静态属性。

prototype分析结论

通过上面代码的验证,你可能会疑问,first的原型明明指向了second,怎么获取不到second原型上的属性呢?这可能是刚接触原型的妹纸们经常犯的一个错误。这里的理解确实比较绕点。其实所有对象的prototype原型机制都是通过对象内部的一个“__proto__”属性指向连接的。高版本浏览器可以直接通过"__proto__"来指定一个对象的原型,IE11一下浏览器不支持访问“__proto__”属性。

我们将上first的代码用“__proto__”改造一下:

second.__proto__={sdate:"2017-1-14"};
second.price="100";
first.prototype=second;

var foo=new first();

console.log(foo.price);
//100

console.log(foo.sdate);
//2014-1-14;

这样foo就可以访问second原型上的属性了。prototype属性也是一个对象,我们使用second.prototype来设置second的原型,其实是设置通过second创建的对象的原型,而通过“__proto__”设置second的原型,才是设置second这个对象上的原型的。

function second(){}
console.log(second.constructor);
//function Function(){[native code]}

console.log((new second).constructor);
//function second(){}

通过second.constructor和(new second).constructor我们可以看出,second的构造函数是Function,而new second创建的实例的构造函数才是second函数本身。

而second.prototype={sdate:"217-1-14"};是给second实例设置了“__proto__”的指针,并没有跟他本身设置原型指针。这时候frist.prototype=second的原型是访问second,而second本身的“__proto__”原型指针是指向“Object”对象的。所以foo访问sdate的流程是下面这样的:

 1,foo本身没有sdate属性

    --->2,foo的原型seond对象也没有sdate属性

       --->3,second的原型Object也没有sdate属性

           ---->4,返回undefined

同理,foo访问price属性,就可以在第2步second对象身上找到price属性。

而three.prototype=new second;  second已经给new second实例指定“__proto__”原型指针到{sdate:"2017-1-14"},所以他可以在new second的原型上找到sdate属性,而new second对象是没有price属性的,所以price为undefined。

prototype属性的静态访问方式

对于prototype原型我们还可以采用静态方式访问

var sdate=second.prototype.sdate;
console.log(sdate);
//2017-1-14.

prototype原型链上的this指针。

 function first(){
 }
 first.prototype={

        say:function(){
            console.log(this);
        },
        init:function(){
            this.say();
        }
 }
 var foo=new first();
foo.init();
//first{}

调用原型上的say方法,在say方法中,this仍然是first创建的对象。原型链中的方法是不改变this指针的,在原型链中的方法中this指针永远指向原始调用对象。所以我们在原型上的init方法中可以通过this调用原型上的其他方法。

prototype的用途

prototype可以封装js使其代码解耦,增强复用性,可以模拟继承。最常用在js插件的写法中。


原创文章,转载请注明来自:妹纸前端-www.webfront-js.com.
阅读(1833)
辛苦了,打赏喝个咖啡
微信
支付宝
妹纸前端
妹纸前端工作室 | 文章不断更新中
京ICP备16005385号-1