讲原型的时候,我们应该先要记住以下几个要点,这几个要点是理解原型的关键:

1、所有的引用类型(数组、函数、对象)可以自由扩展属性(除null以外)。

2、所有的引用类型都有一个’_ _ proto_ _'属性(也叫隐式原型,它是一个普通的对象)。

3、所有的函数都有一个’prototype’属性(这也叫显式原型,它也是一个普通的对象)。

4、所有引用类型,它的’_ _ proto_ _'属性指向它的构造函数的’prototype’属性。

5、当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它的’_ _ proto_ _'属性(也就是它的构造函数的’prototype’属性)中去寻找。

那么要点说完了,我们就根据这些要点来理解原型和原型链。

原型
我们先来看一个原型的例子。

//这是一个构造函数
function Foo(name,age){
this.name=name;
this.age=age;
}
/*根据要点3,所有的函数都有一个prototype属性,这个属性是一个对象
再根据要点1,所有的对象可以自由扩展属性
于是就有了以下写法*/
Foo.prototype={
// prototype对象里面又有其他的属性
showName:function(){
console.log("I'm "+this.name);//this是什么要看执行的时候谁调用了这个函数
},
showAge:function(){
console.log("And I'm "+this.age);//this是什么要看执行的时候谁调用了这个函数
}
}
var fn=new Foo('小明',19)
/*当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它
构造函数的'prototype'属性中去找*/
fn.showName(); //I'm 小明
fn.showAge(); //And I'm 19

这就是原型,很好理解。那为什么要使用原型呢?

试想如果我们要通过Foo()来创建很多很多个对象,如果我们是这样子写的话:

function Foo(name,age){
this.name=name;
this.age=age;
this.showName=function(){
console.log("I'm "+this.name);
}
this.showAge=function(){
console.log("And I'm "+this.age);
}
}

那么我们创建出来的每一个对象,里面都有showName和showAge方法,这样就会占用很多的资源。
而通过原型来实现的话,只需要在构造函数里面给属性赋值,而把方法写在Foo.prototype属性(这个属性是唯一的)里面。这样每个对象都可以使用prototype属性里面的showName、showAge方法,并且节省了不少的资源。

原型链
理解了原型,那么原型链就更好理解了。

#####下面这段话可以帮助理解原型链
根据要点5,当试图得到一个对象的属性时,如果这个对象本身不存在这个属性,那么就会去它构造函数的’prototype’属性中去寻找。那又因为’prototype’属性是一个对象,所以它也有一个’_ _ proto_ _'属性。

那么我们来看一个例子:

// 构造函数
function Foo(name,age){
this.name=name;
this.age=age;
}
Object.prototype.toString=function(){
//this是什么要看执行的时候谁调用了这个函数。
console.log("I'm "+this.name+" And I'm "+this.age);
}
var fn=new Foo('小明',19);
fn.toString(); //I'm 小明 And I'm 19
console.log(fn.toString===Foo.prototype.__proto__.toString); //true

console.log(fn.__proto__ ===Foo.prototype)//true
console.log(Foo.prototype.__proto__===Object.prototype)//true
console.log(Object.prototype.__proto__===null)//true

是不是觉得有点奇怪?我们来分析一下。

首先,fn的构造函数是Foo()。所以:
fn._ _ proto _ _=== Foo.prototype
又因为Foo.prototype是一个普通的对象,它的构造函数是Object,所以:
Foo.prototype._ _ proto _ _=== Object.prototype
通过上面的代码,我们知道这个toString()方法是在Object.prototype里面的,当调用这个对象的本身并不存在的方法时,它会一层一层地往上去找,一直到null为止。

所以当fn调用toString()时,JS发现fn中没有这个方法,于是它就去Foo.prototype中去找,发现还是没有这个方法,然后就去Object.prototype中去找,找到了,就调用Object.prototype中的toString()方法。

这就是原型链,fn能够调用Object.prototype中的方法正是因为存在原型链的机制。

另外,在使用原型的时候,一般推荐将需要扩展的方法写在构造函数的prototype属性中,避免写在_ _ proto _ _属性里面。
---------------------

一文读懂JS中的原型和原型链(图解)的更多相关文章

  1. 一文搞懂 js 中的各种 for 循环的不同之处

    一文搞懂 js 中的各种 for 循环的不同之处 See the Pen for...in vs for...of by xgqfrms (@xgqfrms) on CodePen. for &quo ...

  2. 一文读懂Java中的动态代理

    从代理模式说起 回顾前文: 设计模式系列之代理模式(Proxy Pattern) 要读懂动态代理,应从代理模式说起.而实现代理模式,常见有下面两种实现: (1) 代理类关联目标对象,实现目标对象实现的 ...

  3. 一文看懂js中元素的滚动大小(scrollWidth,scrollHeight,scrollTop,scrollLeft)

    滚动大小(scroll dimension) 滚动大小指的是包含滚动内容元素的大小. 以下是与元素滚动内容大小相关的属性: 1. scrollWidth:在没有滚动条的情况下,元素内容的总宽度. 2. ...

  4. 一文看懂js中元素的客户区大小(clientWidth,clientHeight)

    元素的客户区 元素的客户区大小,指的是元素内容及其内边距所占据的空间大小. 相关属性如下: 1. clientWidth:元素内容区宽度+元素左右内边距 2. clientHeight:元素内容区高度 ...

  5. 一文搞懂js中的typeof用法

    基础 typeof 运算符是 javascript 的基础知识点,尽管它存在一定的局限性(见下文),但在前端js的实际编码过程中,仍然是使用比较多的类型判断方式. 因此,掌握该运算符的特点,对于写出好 ...

  6. 一文读懂BERT中的WordPiece

    1. 前言 2018年最火的论文要属google的BERT,不过今天我们不介绍BERT的模型,而是要介绍BERT中的一个小模块WordPiece. 2. WordPiece原理 现在基本性能好一些的N ...

  7. 一文看懂js中的clientX,clientY,pageX,pageY,screenX,screenY

    一. 客户区坐标位置(clientX,clientY) 鼠标事件都是在浏览器视口中的特定位置发生的.这个位置信息保存在事件对象的clientX和clientY属性中,所有浏览器都支持这两个属性. 我们 ...

  8. 一文看懂js中元素偏移量(offsetLeft,offsetTop,offsetWidth,offsetHeight)

    偏移量(offset dimension) 偏移量:包括元素在屏幕上占用的所有可见空间,元素的可见大小有其高度,宽度决定,包括所有内边距,滚动条和边框大小(注意,不包括外边距). 以下4个属性可以获取 ...

  9. 一文读懂 .NET 中的高性能队列 Channel

    介绍 System.Threading.Channels 是.NET Core 3.0 后推出的新的集合类型, 具有异步API,高性能,线程安全等特点,它可以用来做消息队列,进行数据的生产和消费, 公 ...

随机推荐

  1. HDU 4283:You Are the One(区间DP)

    http://acm.hdu.edu.cn/showproblem.php?pid=4283 题意:有n个数字,不操作的情况下从左到右按顺序输出,但是可以先让前面的数字进栈,让后面的数字输出,然后栈里 ...

  2. while循环的初始以及编码的初始

    whlie循环 why:比如要多次重复做一件事情,如歌曲列表循环,银行卡密码错误多次重复! what:whlie无限循环. how: ##基本结构while 条件:    循环体 基本原理 循环如何终 ...

  3. 最近学习了HBase

    HBase是什么 最近学习了HBase,正常来说写这篇文章,应该从DB有什么缺点,HBase如何弥补DB的缺点开始讲会更有体感,但是本文这些暂时不讲,只讲HBase,把HBase相关原理和使用讲清楚, ...

  4. Vue快速学习_第三节

    过滤器 局部过滤器(组件内部使用的过滤器,跟django的很像, filters: {过滤器的名字: {function(val, a,b){}}} 全局过滤器(全局过滤器,只要过滤器一创建,在任何组 ...

  5. Spring MVC源码(二) ----- DispatcherServlet 请求处理流程 面试必问

    前端控制器 前端控制器,即所谓的Front Controller,体现的是设计模式中的前端控制器模式.前端控制器处理所有从用户过来的请求.所有用户的请求都要通过前端控制器.SpringMVC框架和其他 ...

  6. bzoj3316 JC loves Mkk题解

    3316: JC loves Mkk Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 979  Solved: 316[Submit][Status][Di ...

  7. 学习springboot整合mybatis并编写测试类

    报名立减200元.暑假直降6888. 邀请链接:http://www.jnshu.com/login/1/20535344 邀请码:20535344 遇到的问题: 1.原因是在启动类上只有一个@Map ...

  8. excel报表开发-- 根据datatable个数自动生成新sheet

    总结一下很久之前做的报表小程序,今日有问题又调试了一下. DB中存在一个表,记录了ID<自增长>,SqlStatement<sql查询语句>及其他必要字段,比如SheetNam ...

  9. vue-cli安装搭建初始项目

    vue-cli脚手架 前提:node + npm 安装好 一.介绍 vue-cli: Vue + ESLint + webpack + iview + ES6 Vue:主要框架ESLint:帮助我们检 ...

  10. 个人永久性免费-Excel催化剂功能第100波-透视多行数据为多列数据结构

    在数据处理过程中,大量的非预期格式结构需要作转换,有大家熟知的多维转一维(准确来说应该是交叉表结构的数据转二维表标准数据表结构),也同样有一些需要透视操作的数据源,此篇同样提供更便捷的方法实现此类数据 ...