先以一段简单的代码为例:
function Dog(params){
    this.name = param.name;
    this.age = param.age;
    this.bark = function(){
        console.log("汪汪汪!!!");
    };
}
var wc = new Dog({name:"旺财",age:3});
 
 
console.log(Dog.prototype)函数的原型属性
在上面这段代码里,Dog是构造函数(区别普遍函数,构造函数一般大写);wc是构造函数Dog的实例对象。 
那么我们说:当构造函数创建时,会存在一个神秘对象。构造函数的prototype属性(保存着该构造函数的方法和属性)指向该神秘对象,实例化对象的__proto__会指向该神秘对象。
这个神秘对象就是原型。 
wc.__proto__ == Dog.prototype == 原型所在的地址 
下图描述了这种关系: 
构造函数有原型属性,实例对象有原型继承 

原型的两种使用方式

前面说过,我们一旦定义一个函数对象,系统会自动给这个函数对象附上原型属性prototype,这是默认原型链结构

沿用默认原型链结构

Dog.prototype.bark = function(){ console.log("汪汪汪!!!"); }
这样子做,只是给Dog.prototype新添加了一个方法bark,没有破坏默认原型链结构
替换默认原型链结构
Dog.prototype = {
    bark:function(){
    console.log("汪汪汪!!!");
    }
}
这样子做,Dog.prototype指向了新的内存地址,丢失了默认原型链结构的一些默认方法,比如constructor 
下图说明了这两种方式的区别: 

原型的作用

原型的作用是为了实现继承  提高代码的复用
同样的,我们看一段代码:
function Dog(param){
    this.name = param.name;
    this.age = param.age;
    this.bark = function(){
        console.log("汪汪汪!!!");
    };
}
var wc = new Dog({name:"旺财",age:3});
var dh = new Dog({name:"大黄",age:2});
同样的,我们看一下内存分析图: 
console.log(wc.bark == dh.bark);//结果为false
把公有的方法存放在构造函数的原型中,实例对象本身并不存放该方法。这样子做,不论构造函数创建多少个实例,该公有方法始终只存在一个。 
这大大减少了内存的浪费
也许有人会问:在你的图上面wc和dh并没有bark方法,那么它们怎么能调用Dog.prototype里的bark方法?
原因就是js的原型继承特性,在后面谈到原型链的时候会做详细的探讨
 
也许有人会问:既然把公有方法都放在构造函数的原型属性里能节省内存,那么为什么不把name,age等属性也都放在里面呢?
这样做是不对的,对象有共性和特性。比如人都会吃饭睡觉,这是共性。但不同的人姓名年龄不同,这是特性。我们把共性放在原型里,只维护一个。但是特性要放在构造函数里

原型链结构

前面已经说了原型的作用是为了实现继承,提高代码的复用。那么原型实现继承的方法是什么呢?使用原型链! 
何为继承?子类把父类的方法拿来自己用。 
举个栗子:动物会吃饭睡觉,狗继承自动物,于是狗也会了吃饭睡觉;狗会吠叫,旺财和大黄继承自狗,于是旺财也会吠叫 
于是旺财—->狗—->动物就形成了一条链,js原型也有一条类似的链叫做原型链
这条链的原则是:A是B的构造函数 那么(实例化对象__proto__)B.__proto__ == A.prototype;prototype保存着该函数的属性和方法
如上诉的代码:Dog是wc的构造函数 那么wc.__proto__ == Dog.prototype,wc可以使用Dog.prototype里的属性和方法
我们再往上找找原型链吧!
Dog.prototype.__proto__ 是什么? 因为Dog.prototype是Obejct对象,所以Dog.prototype.__proto__ == Object.prototype
Dog.__proto__ 是什么?因为Dog是构造函数,是Function对象,所以Dog.__proto__ == Function.prototype
我们不妨画一下上面的原型链示意图:
Function和Object
这两位都是大佬级的角色了:Function是一切函数的起始,Object是一切对象的起始,他们怎么干一架呢?
    
1.Object也是一个构造函数,只要是函数都是Function的实例,所以:Object.__proto__ == Function.prototype
2.Function也是一个构造函数,所以: Function.__proto__ == Function.prototype
3.Function.prototype是一个”对象?”,所以:Function.prototype.__proto__ == Object.prototype
4.Object.prototype.__proto__ == null
这里有一个巨坑:typeof Function.prototype 结果是function 我也不知道为什么,知道原因的大神请不吝赐教^-^

详聊js中的原型/原型链的更多相关文章

  1. 面试题常考&必考之--js中的难点!!!原型链,原型(__proto__),原型对象(prototype)结合例子更易懂

    1>首先,我们先将函数对象认识清楚: 补充snow的另一种写法: var snow =function(){}; 2>其次:就是原型对象 每当我们定义一个函数对象的时候,这个对象中就会包含 ...

  2. js中的prototype原型解析

    在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不 ...

  3. js中函数的原型

    js中每一个构造函数都有一个prototype的属性,prototype指向一个对象,而这个对象的属性和方法都会被构造函数的实例所继承,因此,需要一些共享的属性和方法可以写在构造函数的原型中 1  用 ...

  4. js中构造函数的原型添加成员的两种方式

    首先,js中给原型对象添加属性和方法. 方式一:对象的动态特效 给原型对象添加成员 语法:构造函数.prototype.方法名=function (){ } 方式二:替换原型对象(不是覆盖,而是替换, ...

  5. 详解js中的闭包

    前言 在js中,闭包是一个很重要又相当不容易完全理解的要点,网上关于讲解闭包的文章非常多,但是并不是非常容易读懂,在这里以<javascript高级程序设计>里面的理论为基础.用拆分的方式 ...

  6. 详解js中的寄生组合式继承

    寄生组合式继承是js中最理想的继承方式, 最大限度的节省了内存空间. js中的寄生组合式继承要求是: 1.子对象有父对象属性的副本, 且这些不应该保存在子对象的prototype上.       2. ...

  7. 详解JS中DOM 元素的 attribute 和 property 属性

    一.'表亲戚':attribute和property 为什么称attribute和property为'表亲戚'呢?因为他们既有共同处,也有不同点. attribute 是 dom 元素在文档中作为 h ...

  8. js中使用使用原型(prototype)定义方法的好处

    经常在前端面试或是和其他同行沟通是,在谈到构造在JS定义构造函数的方法是最好使用原型的方式:将方法定义到构造方法的prototype上,这样的好处是,通过该构造函数生成的实例所拥有的方法都是指向一个函 ...

  9. js中__proto__(内部原型)和prototype(构造器原型)的关系

    一.所有构造器/函数的__proto__都指向Function.prototype,它是一个空函数(Empty function) Number.__proto__ === Function.prot ...

随机推荐

  1. jq元素左边距

    获取页面某一元素的绝对X,Y坐标,可以用offset():var X = $(‘#DivID’).offset().top;var Y = $(‘#DivID’).offset().left; 获取相 ...

  2. sift特征点检测和特征数据库的建立

    类似于ORBSLAM中的ORB.txt数据库. https://blog.csdn.net/lingyunxianhe/article/details/79063547   ORBvoc.txt是怎么 ...

  3. SpringCloud 教程 (四) docker部署spring cloud项目

    一.docker简介 Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移植的.自给自足的容器.开发者在笔记本上编译测试通过的容器可以批量地在生产环境中部署,包括VMs(虚拟机). ...

  4. SQL字串截取函数编写及应用

    SQL里面一种用来截取字符串的方法,用的是表函数实现字符串截取并应用的SQL操作语句中. .截取字符串表函数 ALTER FUNCTION [dbo].[SplitToTable] ( -- Add ...

  5. es之得分(加权)

    随着应用程序的增长,提高搜索质量的需求也进一步增大.我们把它叫做搜索体验.我们需要知道什么对用户更重要,关注用户如何使用搜索功能.这导致不同的结论,例如,有些文档比其他的更重要,或特定查询需强调一个字 ...

  6. POJ 1383 Labyrinth (bfs 树的直径)

    Labyrinth 题目链接: http://acm.hust.edu.cn/vjudge/contest/130510#problem/E Description The northern part ...

  7. 深入理解JVM虚拟机11:Java内存异常原理与实践

    本文转自互联网,侵删 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutori ...

  8. 前端每日实战:138# 视频演示如何用纯 CSS 创作一张 iPhone 价格信息图

    效果预览 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/OorLGZ 可交互视频 此视频是可 ...

  9. fedora23禁用不需要的服务?--systemd服务单元?

    sign up: 签约; 登记, 注册. i'll sign up and go to the front and fight. he persuaded the company to sign up ...

  10. 阶段1 语言基础+高级_1-3-Java语言高级_04-集合_06 Set集合_7_可变参数

    打印出来是一个数组的地址 打印数组的长度 只要调用了add方法就会创建一各长度为0的数组 传一个10过去.就输出了数组的长度为1 传两个数字 注意事项: 特殊写法