Js原型链解读

作者: vzardlloo | 来源:发表于2017-11-07 19:11 被阅读83次

前言

在JavaScript中没"子类”和“父类”的概念,进一步地也没有“类”和“实例”的的区分。它靠一种看上去十分古怪的”原型链“(prototype chain)模式来实现继承。学过JAVA等编程语言的人可能会认为这是对Java等语言的继承实现方式的一种拙劣并且失败的模仿,然而事实并非如此,原型链模式和我们常见的Class模式分别是两种编程范式prototype_base和class_base的实现,前者在动态语言中似乎十分常见,而后者主要在静态语言领域流行。下面是维基百科关于prototype_base模式的介绍:

Prototype-based programming is a style of object-oriented programming in which behaviour reuse (known as inheritance) is performed via a process of reusing existing objects via delegation that serve as prototypes. This model can also be known as prototypal, prototype-oriented, classless, or instance-based programming. Delegation is the language feature that supports prototype-based programming.
Prototype object oriented programming uses generalized objects, which can then be cloned and extended. Using fruit as an example, a "fruit" object would represent the properties and functionality of fruit in general. A "banana" object would be cloned from the "fruit" object, and would also be extended to include general properties specific to bananas. Each individual "banana" object would be cloned from the generic "banana" object. Compare to the class-based paradigm, where a "fruit" class (not object) would be extended by a "banana" class

维基原文

如何理解原型链

我们以一个名字叫Foo()的函数为例。我们定义:

function Foo(){


}

然后再var f1 = new Foo(),var f2 = new Foo(),这期间都有什么事情发生呢?我们通过一张图来看一下:

prototype.jpg

先介绍两个概念:_proto_prototype:

  • _proto_:引用《JavaScript权威指南》中的说明:

Every JavaScript object has a second JavaScript object (or null ,
but this is rare) associated with it. This second object is known as a prototype, and the first
object inherits properties from the prototype.
就是说就是每个JS对象一定对应一个原型对象,并从原型对象继承属性和方法。既然有这么一个原型对象,那么对象怎么和它对应的?如何描述这种对应关系?答案就是通过_proto_,对象__proto__属性的值就是它所对应的原型对象。

  • prototype: 与_proto_不同,prototype是函数才有的属性。当你创建函数时,JS会为这个函数自动添加prototype属性,值是空对象。而一旦你把这个函数当作构造函数(constructor)调用(即通过new关键字调用),那么JS就会帮你创建该构造函数的实例,实例继承构造函数prototype的所有属性和方法(实例通过设置自己的__proto__指向承构造函数的prototype来实现这种继承)。它的存在主要是为了存放共享的数据和实现继承。

  下面结合上面的图示来分析,我们可以看到function Foo()对应一个Foo.prototype的原型,那么function FooFoo.prototype之间的关系是什么尼?
  图里其实已经展示得很清楚了,functon Foo()Foo.prototype的构造函数,Foo.prototypefunction Foo()的原型实例。当我们使用new关键字创建var f1 = new Foo(),var f2 = new Foo()后,f1、f2中会有一个_proto_字段指向Foo.prototype,这种xxx._proto_._proto....的指向就代表了原型链的结构(应该是个森林)。同时每个函数function xxx()其实都是通过function Function()来创造的,所以function Foo()_proto_应该指向Function.prototype,并且function Function()自身的_proto_也指向Function.prototype
  事实上,所有function xxx()_proto_最终都会指向Function.prototype,而所有的xxx.prototype最后都会指向Object.prototype,最终指向null。关于function Object()这个函数其实有点像Java中的Object对象,所有原型都会继承自它的原型。这里有个有意思的问题,function Function()也是个函数,所以function Function()_proto_属性的值为Function.prototype,这也就意味着它自己创造了自己。这样的结果就是function Object()._proto_ = Function.prototype、而function Function()._proto._proto_ = Object.prototype,即Object instanceof Function == trueFunction instanceof Object == true翻译过来就是ObjectFunction的实例,FunctionObject的实例,这是一种类似先有鸡还是先有蛋的蜜汁尴尬局面。

总结:

  • 所有对象的_proto_字段都指向创建它的构造函数的原型, 最终都指向Object.prototype,类似xxx.prototype._proto_._proto_..._proto_ = Object.prototype = null就是原型链。
  • 所有函数都由function Function()创建,所以所有函数的(包括它本身)_proto_字段都会指向Function.prototype,最后才指向Object.prototype

使用原型链实现继承

定义父函数:

function Father() {
    this.age = "56"; }

Father.prototype.say = function () {
    alert("my age is "+this.age); 
} 

定义子函数:

function Son() {
    this.age = '26';
  this.play = "football"; }

Son.prototype.play = function () {
    alert("I like play "+this.play);
 }

实现继承后的原型链应该是:Son.prototype._proto_ = Father.prototype
实现方式:借用第三个函数过渡

function extends(Child,Father){
    var F = function(){};
    F.prototype = Father.prototype;
    //Child.prototype._proto_ = F.prototype = Father.prototype
    Child.prototype = new F();
    //原本Child.prototype.constructor = F,修改为Child
    Child.prototype.constructor = Child;
    
}

测试验证:Son的实例可以调用say()则说明继承成功。

    function Father() {
    this.age = "56"; }

    Father.prototype.say = function () {
    alert("my age is "+this.age); }

    function Son() {
    this.age = '26';
    this.play = "football"; }

    Son.prototype.play = function () {
    alert("I like play "+this.play); }

    function excents(Child,Father) {

    var F = function () {}
    F.prototype = Father.prototype;
    Child.prototype = new F();
    Child.prototype.constructor = Child;   }

    excents(Son,Father);  

    var son = new Son(); 
    son.say();

运行结果:


image

继承成功!

相关文章

  • Js原型链解读

    前言 在JavaScript中没"子类”和“父类”的概念,进一步地也没有“类”和“实例”的的区分。它靠一种看上去十...

  • 廖雪峰JS小记

    (function(){})() 原型,原型链 浅谈Js原型的理解JS 原型与原型链终极详解 对象 对象:一种无序...

  • JS的__proto__和prototype

    最近在回顾JS的原型和原型链的知识,熟悉JS的同学都知道JS的继承是靠原型链实现的,那跟原型链相关的属性__pro...

  • Javascript(三)之原型继承理解

    进阶路线 3 原型继承 3.1 优秀文章 最详尽的 JS 原型与原型链终极详解 一 最详尽的 JS 原型与原型链终...

  • 从实现角度分析js原型链

    从实现角度分析js原型链 欢迎来我的博客阅读:《从实现角度分析js原型链》 网上介绍原型链的优质文章已经有很多了,...

  • JS原型链

    1什么是JS原型链? 通过__proto__属性将对象与原型对象进行连接. 1.1 JS原型链的作用? 组成的一个...

  • 关于JS中的原型和原型链

    目录 关于js 对象和原型 原型链 基于原型链的继承 参考资料ECMAScript 6 入门JavaScript原...

  • js_继承及原型链等(四)

    js_继承及原型链等(三) 1. 继承 依赖于原型链来完成的继承 发生在对象与对象之间 原型链,如下: ==原型链...

  • 2022前端高频面试题

    JS相关 1.原型和原型链是什么 原型和原型链都是来源于对象而服务于对象的概念js中引用类型都是对象,对象就是属性...

  • JavaScript原型链

    js原型链 原型链是JS面向对象的基础非常重要 所有对象只有__proto__属性,而函数具有prototype属...

网友评论

    本文标题:Js原型链解读

    本文链接:https://www.haomeiwen.com/subject/jmzjmxtx.html