最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 科技 - 知识百科 - 正文

JS中的原型链详解

来源:动视网 责编:小采 时间:2020-11-27 19:58:33
文档

JS中的原型链详解

JS中的原型链详解:JS虽然不是面向对象类型的语言,但这不并不意味着JS就不能够实现OOP的特性。 我相信大家在使用JS的时候,一定用过Object的原型方法,比如call,apply,hasOwnProperty等等方法,可是这些方法是从哪里来的呢?如果JS无法实现继承的话,这些方法的使用就无从谈起
推荐度:
导读JS中的原型链详解:JS虽然不是面向对象类型的语言,但这不并不意味着JS就不能够实现OOP的特性。 我相信大家在使用JS的时候,一定用过Object的原型方法,比如call,apply,hasOwnProperty等等方法,可是这些方法是从哪里来的呢?如果JS无法实现继承的话,这些方法的使用就无从谈起


而构造函数的原型对象的默认值为:

 Person.prototype={
 constructor://指向构造函数本身
 _proto_://指向构造函数Person的原型对象的构造函数的原型对象,这里是指Object.prototype
 }
 //这里有一个特殊情况——当构造函数为Function的时候
 Function.prototype._proto_===Object.prototype 
 //我们知道Function.prototype是一个函数对象,它的_proto_应该指向它的构造函数的原型,也就是Function.prototype。
 //可是这样下去就没完没了了,毕竟一条链总是有顶端的。这里约定Function.prototype._proto_===Object.prototype; //这时,Object.prototype._proto_===null;完美结束原型链。

我们可以不断修改构造函数的原型对象的指向,这样最终就可以形成一条链。而上面提到的一条链就是JS中的默认原型链。

谈谈代码实现

下面我们看看代码:

 function Parent(name){
 this.name=name||"parent";
 } function Son(name){
 this.name=name||"son"; this.property="initial Son name";
 } function Grandson(name){
 this.name=name||"grandson"; this.ggs="initial Grandson name";
 }

 Son.prototype = new Parent("原型中的Parent");
 Grandson.prototype = new Son("原型中的Son"); let grandson = new Grandson("孙子");
 console.log(grandson instanceof Son);//true
 console.log(grandson instanceof Grandson);//true
 console.log(grandson instanceof Parent);//true


很显然,最后都输出true。但是我们改动一点代码:

 Grandson.prototype = new Son("原型中的Son");
 Son.prototype = new Parent("原型中的Parent");//其实上一步已经实例化了一个Son的对象给Grandson.prototype
 //这个时候Son的实例的_proto_已经确定指向那个时候的构造函数.prototype了(默认原型对象)
 let grandson = new Grandson("孙子");
 console.log(grandson instanceof Son);//false
 console.log(grandson instanceof Grandson);//true
 console.log(grandson instanceof Parent);//false


为什么结果会变呢?原因也很简单。我们之前有提到对象的创建的创建过程:对象在实例化的时候就已经给对象的_proto_赋了构造函数的prototype了。也就是说上面代码中第一行已经确定了Grandson.prototype._proto_的值了,即使在第二行修改了Son.prototype也是无法修改Grandson.prototype._proto_的值。

Conclusion:JS中原型链的关系是由_proto_维持的,而不是prototype。

小测试

var animal = function(){}; var dog = function(){};

 animal.price = 2000;
 dog.prototype = animal; var tidy = new dog();
 console.log(dog.price) 
 console.log(tidy.price)

答案是输出什么呢?是undefined和2000,我们分析一下:
首先我们清楚animal和dog都是函数对象,在第四行修改了dog的原型对象为animal。那么我们接着往下看,console.log(dog.price) 这一句首先会寻找dog的price,没有。然后去原型链上寻找。怎么找的呢?我们之前提到是通过_proto_去到它构造函数的原型对象上,这里因为dog是函数对象,那么它的构造函数的原型对象就是Function.prototype,这是一个empty function。于是返回undefined,没有找到price这个属性。
那么console.log(tidy.price) 呢?
tidy是一个普通对象,首先也是寻找它本身的属性price,也没有。通过_proto_去到它构造函数的原型对象上,也就是dog.prototype。因为tidy实例化在dog.prototype = animal; 之后,所以tidy._proto_的指向已经指向了修改后的dog.prototype。也就是指向了animal,也就是能够找到price这个属性了,所以输出2000。

原型对象上的所有属性和方法都可以看成是Java中父类的public(protected)属性和方法,在这些方法内部使用this即可访问构造函数中的属性和方法。至于为什么,这又得提到JS中this的绑定问题了….总而言之,谁调用的函数,this就指向谁。箭头函数除外…

相关推荐:

详解JS原型和原型链(一)

详解JS原型和原型链(二)

详解JS原型和原型链(三)

文档

JS中的原型链详解

JS中的原型链详解:JS虽然不是面向对象类型的语言,但这不并不意味着JS就不能够实现OOP的特性。 我相信大家在使用JS的时候,一定用过Object的原型方法,比如call,apply,hasOwnProperty等等方法,可是这些方法是从哪里来的呢?如果JS无法实现继承的话,这些方法的使用就无从谈起
推荐度:
标签: 中的 js 详解
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top