博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【前端Talkking】JS-一步一步掌握Javascript中的原型与原型链
阅读量:6451 次
发布时间:2019-06-23

本文共 5621 字,大约阅读时间需要 18 分钟。

0.写在前面

如果大家想深入学习Javascript编程语言,Javascript中的原型及原型链是必须掌握的。当初我在学习原型及原型链的时候,就遇到过不少阻碍,希望通过我的这篇文章,能够让你真正的掌握JavaScript中的原型及原型链。好啦,开始我们的原型及原型链的旅途吧~

在介绍Javascript原型之前,我们先来了解一段历史。

1.Javascript继承机制的设计思想

1994年,网景公司发布了Navigator浏览器0.9版,当时这个版本的浏览器只能用来浏览,并不具有与用户用户进行互动的功能,比如说,要判断用户是否填写了表单数据,只能通过服务器来进行判断,这样会带来一个弊端:极大的浪费了带宽以及服务器资源。在这种情况下,就需要一种脚本语言,这种语言能够与浏览器进行交互,Brendan Eich负责开发这种脚本语言(也就是Javascript),当时,这位工程师认为这种脚本语言不需要设计的太复杂,只需完成简单操作即可,比如判断用户是否填写了表单数据。此时,我们还要了解下当时的编程语言背景,在1994年的时候,C++是最兴盛的面向对象的编程语言,Java1.0也将于第二年推出,Brendan Eich也将Javascript设计为面向对象的语言,在Javascript中一切皆对象。当时,他遇到了一个难题,到底需不需要将继承机制引入Javascript中?最终的结果是,也许他受到了C++和Java的影响,继承机制最终被引入到Javascript编程语言中。

下面我们来看看在C++中生成一个对象的方法:

A *a=new A(param);

而在Java中生成一个对象的方法:

Foo foo=new Foo();

我们再来看看Javascript生成一个对象的方法:

function Dog(name){    this.name=name;}

var dogA = new Dog("旺旺");

alert(dogA.name);//旺旺
我们再来看看Javascript中另外一种写法:

function Dog(name){    this.name=name;    this.species ="犬科";}var dogA = new Dog("旺旺");dogA.species="猫科";var dogB = new Dog("旺旺2");alert(dogB.species);//犬科

在这个例子中,生成了两个对象dogA与dogB,dogA修改了species,但是我们访问dogB的species,还是原来的值。于是,我们可以看出通过这种方法生成的实例对象,每个对象都有自己的属性和方法的副本,实例对象间不能做到属性的方法的共享,这样带来的一个缺点就是极大的浪费了系统的资源。有没有改进的方法呢?有,肯定有!

2.Javascript中原型(prototype)的引入

考虑到上面的不足,这位工程师决定给每个构造函数添加一个prototype属性,这个属性指向一个对象,称为prototype对象。在Javascript中,一切皆对象,对象可以分为三类:实例对象(通过new和构造函数创建出来的对象)、函数对象(一般也称为函数)、原型对象(函数对象的prototype属性所指向的对象)。我们首先来看下实例对象中的属性和方法,如下图:

图片描述

实例一旦创建,将自动引用prototype对象的方法和属性,也就是说,针对实例对象而言,它的属性和方法可以分为两种:一种是本地的,另外一种是引用的。

prototype、_proto_和constructor三角关系

我将用下面的一副图来描述三者的关系:

图片描述

我将上幅图总结为下面几点内容:

  • 任何函数对象都有prototype属性,它指向对应的原型对象,表示其实例对象的原型对象;
  • 任何原型对象都有一个constructor属性,它指向对应的函数对象;

任何对象都有一个隐藏的_proto属性,它是对原型对象的引用;

  • _proto_属性不是一个规范的属性,只是部分浏览器实现了此属性(如chrome和Firefox),如果想访问对象的原型,可以使用Object.getPrototype(object)访问。

一定要牢记上面的几点内容,它将对后面的内容非常重要。

3 原型实例分析

说明:后面的实例,如果看不懂,可以再看看前面的内容,好好理解下前面的内容,一定可以理解后面的例子的。同时,下面的例子运行结果我会有一定的解释。

step1:查看对象的原型

function Person(name, age){    this.name = name;    this.age = age;     this.getInfo = function(){        console.log(this.name + " is " + this.age + " years old");    }}var will = new Person("Will", 28);console.log(will.__proto__);console.log(will.constructor);

运行结果:

图片描述

解释:will对象本身并没有"constructor"这个属性,但是通过原型链查找,找到了will原型(will.__proto__)的"constructor"属性,并得到了Person函数

对象之间的关系:

step2:查看对象will原型的原型

function Person(name, age){    this.name = name;    this.age = age;     this.getInfo = function(){        console.log(this.name + " is " + this.age + " years old");    }}console.log(will.__proto__ === Person.prototype);console.log(Person.prototype.__proto__);console.log(Person.prototype.constructor);console.log(Person.prototype.constructor === Person);

运行结果:

图片描述

对象之间的关系

图片描述

step3:查看对象Object的原型

function Person(name, age){    this.name = name;    this.age = age;     this.getInfo = function(){        console.log(this.name + " is " + this.age + " years old");    }}console.log(Person.prototype.__proto__ === Object.prototype);console.log(typeof Object);console.log(Object);console.log(Object.prototype);console.log(Object.prototype.__proto__);console.log(Object.prototype.constructor);

运行结果:

图片描述
对象之间的关系:
图片描述

step4:查看函数对象的原型

function Person(name, age){    this.name = name;    this.age = age;     this.getInfo = function(){        console.log(this.name + " is " + this.age + " years old");    }}console.log(Person.__proto__ === Function.prototype);console.log(Person.constructor === Function)console.log(typeof Function);console.log(Function);console.log(Function.prototype);console.log(Function.prototype.__proto__);console.log(Function.prototype.constructor);

运行结果:

图片描述

对象之间的关系:

图片描述

4 通过原型改进实例-实现继承

step1:最老的方式

function Person(name, age){    this.name = name;    this.age = age;     this.getInfo = function(){        console.log(this.name + " is " + this.age + " years old");    }}var will = new Person('Will',28);var wilber = new Person("Will", 20);

对象之间的关系:

step2:通过原型prototype实现继承

function Person(name, age){    this.name = name;    this.age = age;    }Person.prototype.getInfo = function(){    console.log(this.name + " is " + this.age + " years old");}

对象之间的关系:

图片描述

5 原型链

什么是原型链?

由于_proto_是任何对象都有的属性,而Javascript中万物皆对象,所以会形成一条_proto_连接起来的链条,递归访问_proto_必须最终到头,并且值为null。

原型链有什么作用?
属性查找与隐藏:当Javascript引擎查找对象的属性时,先查找对象本身是否存在该属性,如果不存在,再沿着_proto_这条链向上查找,但不会查找自身的prototype。

var A = function(){};var a = new A();

以上面的这幅图为例,查找某个属性的时候,会沿着这条原型链进行查找,直到为null。

原型链之属性查找

function Person(name, age){        this.name = name;        this.age = age;     }    Person.prototype.MaxNumber = 9999;    Person.__proto__.MinNumber = -9999;    var will = new Person("Will", 28);    console.log(will.MaxNumber);// 9999    console.log(will.MinNumber);//undefined

原型链之属性隐藏

function Person(name, age){    this.name = name;    this.age = age; }Person.prototype.getInfo = function(){    console.log(this.name + " is " + this.age + " years old");    }var will = new Person("Will", 28);will.getInfo = function(){    console.log("getInfo method from will instead of prototype");//};will.getInfo();

对象创建方式影响原型链的构成

var July = {    name: "July",    age: 28,    getInfo: function(){        console.log(this.name + " is " + this.age + " years old");    },}console.log(July.getInfo());

hasOwnProperty

var will = new Person('Will',28);    var wilber = new Person("Will", 20);    for(var attr in will){        console.log(attr);    }        console.log('---------------');    for(var attr in wilber){        if(will.hasOwnProperty(attr)){            console.log(attr);        }    }

6.总结

  • 在Javascript中,通过原型(prototype)实现了对象的继承;
  • 在Javascript中,一切皆对象,prototype、_proto_与constructorJavascript中所有的对象关联起来;
  • 原型链可以实现对象属性的查找和隐藏; hasOwnProterty函数可以用来判断属性是对象本地属性还是原型链上的属性;
    相信到这里,你已经掌握了Javascript中的原型和原型链的知识点了。

欢迎关注我的微信公众号。您的支持将鼓励我继续创作!

图片描述

转载地址:http://yqgwo.baihongyu.com/

你可能感兴趣的文章
linux系统可用内存减少,在Linux中检查可用内存的5种方法
查看>>
linux 脚本map,Linux Shell Map的用法详解
查看>>
如何在linux系统下配置共享文件夹,如何在windows和Linux系统之间共享文件夹.doc
查看>>
thinkpad装linux无线网卡驱动,ThinkPad E530 Fedora 20 下无线网卡驱动的安装
查看>>
linux操作系统加固软件,系统安全:教你Linux操作系统的安全加固
查看>>
linux中yum源安装dhcp,24.Linux系统下动态网络源部署方法(dhcpd)
查看>>
linux屏幕复制显示出来的,linux – stdout到gnu屏幕复制缓冲区
查看>>
一起学Shell(十)之可称植性议题与扩展
查看>>
部署Ganglia监控Hadoop&Hbase
查看>>
gitlab的用户使用手册
查看>>
论Optimizer的工作模式ALL_ROWS&FIRST_ROWS
查看>>
生产环境高并发MySQL SQL语句优化案例
查看>>
Lync 小技巧-24-PDF 加密文件-转-Word-操作手册
查看>>
ASP.NET性能优化之分布式Session
查看>>
TaffyDB Introduction
查看>>
Piwik 1.9.1 发布,网站访问统计系统
查看>>
【转】ie6 png 透明终极解决方案
查看>>
CentOS6.5菜鸟之旅:关于搜索的shell命令
查看>>
扩展ViewFlow避免和ViewPager滑动冲突,同时支持无限循环,并完美和CircleFlowIndicator结合...
查看>>
VC++之自定义消息
查看>>