先以一段简单的代码为例:
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. Day_02-Python的分支结构和循环结构

    分支结构 应用场景 迄今为止,我们写的Python代码都是一条一条语句顺序执行,这种结构的代码我们称之为顺序结构.然而仅有顺序结构并不能解决所有的问题,比如我们设计一个游戏,游戏第一关的通关条件是玩家 ...

  2. Solr分组查询

     项目中需要实时的返回一下统计的东西,因此就要进行分组,在获取一些东西,代码拿不出来,因此分享一篇,还是很使用的. facet搜索 /** * * 搜索功能优化-关键词搜索 * 搜索范围:商品名称.店 ...

  3. Behaviour Tree Service 中的几个函数

    Service中可以override的函数有8个,因为每个函数都有个AI版本的,所以实际上是4组函数,AI版本的和非AI版本基本一样, 他们分别是: Receive Search Start (AI) ...

  4. SpringMVC常用方法总结

    *) @RequestMapping(value="/xxx/{id}",method={RequestMethod.GET}) method 不写的话,默认GET.POST都支持 ...

  5. slider组件

    slider组件,是一个强大的滑动选择器组件: 属性: min:类型 数字 滑动选择器的(范围)最小值 max:类型 数字 滑动选择器的(范围)最大值 step:类型 数字 步长(滑一次走的距离)  ...

  6. React Native商城项目实战15 - 首页购物中心

    1.公共的标题栏组件TitleCommonCell.js /** * 首页购物中心 */ import React, { Component } from 'react'; import { AppR ...

  7. 【C++进阶:STL常见性质】

    STL中的常用容器包括:顺序性容器(vector.deque.list).关联容器(map.set).容器适配器(queue.stac) 转载自:https://blog.csdn.net/u0134 ...

  8. (一)Maven之使用入门

    目录 今天是端午节哦,昨天大学同学举个了会.鱼头泡饼贼拉香,嗯哼,有点跑题了:之后去了同学家里坐了坐:发现同我有一样的书,即:<maven实战>:记得是从二手网店淘到的,已经买了有小半年, ...

  9. java.lang.NoClassDefFoundError: com/opensymphony/xwork2/util/finder/DefaultClassFinder$InfoBuildingV 解决方法

    问题:严重: Unable to read class [com.spml.action.AddUserAction]java.lang.NoClassDefFoundError: com/opens ...

  10. 腾讯重磅开源分布式NoSQL存储系统DCache

    当你在电商平台秒杀商品或者在社交网络刷热门话题的时候,可以很明显感受到当前网络数据流量的恐怖,几十万商品刚开抢,一秒都不到就售罄:哪个大明星出轨的消息一出现,瞬间阅读与转发次数可以达到上亿.作为终端用 ...