js中的对象分为两种:普通对象object和函数对象function。

    function fn1(){};
var fn2 = function(){};
var fn3 = new Function();
var fn4 = Function(); var obj1 = new fn1();
var obj2 = {};
var obj3 = new Object();
var obj4 = Object(); console.log(typeof fn1);//function
console.log(typeof fn2);//function
console.log(typeof fn3);//function
console.log(typeof fn4);//function console.log(typeof obj1);//object
console.log(typeof obj2);//object
console.log(typeof obj3);//object
console.log(typeof obj4);//object

  还有就是所有的构建函数比如Function、Object、Number等等都是函数对象,这个共知的。

    //所有的构建函数都是function类型的
console.log(typeof Object);//function
console.log(typeof Function);//function
console.log(typeof Number);//function

  所有的这类构建函数使用new或者直接调用方式都能构建出一个新的数据类型。但是构建出来的数据有区别的

    var o = new Object(),
o1 = Object();
console.log(o == o1);//false
console.log(o === o1);//false var f = new Function(),
f1 = Function();
console.log(f == f1);//false
console.log(f === f1);//false var a = new Array(),
a1 = Array();
console.log(a == a1);//false
console.log(a === a1);//false var n = new Number(),
n1 = Number();
console.log(n == n1);//true
console.log(n === n1);//false var s = new String(),
s1 = String();
console.log(s == s1);//true
console.log(s === s1);//false var b = new Boolean(),
b1 = Boolean();
console.log(b == b1);//true
console.log(b === b1);//false //数据类型null/undefined是没有构造函数的

  上面的例子中Object/Function/Array的对比结果都好说,因为他们构建出来的都是新的对象,对象比较是要比较根源(数据是否是同一个)。无论是使用new还是直接调用生成一个新的对象是要开辟新的空间存储的,不会和任何一个对象相等。

  但是对于数值类型,比较符“==”只是比较值相等,比较符"==="除了比较值以外还要比较数据类型。

  那么构建数值类型比较为什么呈现上面的样子?

  我们以Number为例。实际上new Number()构建出来的变量n是一个特殊的对象,chrome上的展示如下

  

  只不过这个对象和数值类型比较的时候被当做数值类型来比较。当使用“===”的时候比较数值相等时再比较数据类型的时候是有别于其他数值类型的。

  上面提到了和数值类型比较的时候才成立,如果这个对象和其他对象比较则使用对象比较的规则。

  比如下面的例子

var num = new Number(0);
var str = new String(0);
var str1 = String(0);
console.log(num == str);//false
console.log(num == str1);//true
console.log(num === str1);//false

  num和str都是比较特殊的对象,str1为数值类型。num和str比较实用对象比较的规则来,num和str1比较实用数值比较的规则来。

  上面分析了那么多,现在进入正题。

  普通对象是没有prototype属性的,只有隐藏属性__proto__(IE上也有该隐藏属性,但是使用obj.__proto__不能输出东西,所以建议不要使用__proto__属性)。而函数对象则两者兼有。prototype属性指向的是函数对象的原型对象,对象的__proto__属性是创建实例对象的时候对应的函数对象的原型对象。

a.函数对象的原型对象(fn.prototype)


  这里我们需要理解原型对象的值是怎么来的。原型对象的值实际上就是在函数创建的时候,创建了一个它的实例对象并赋值给它的prototype。过程如下(以Function为例)

var temp = new Function();
Function.prototype = temp;

  所以我们看一下熟知的函数的原型对象吧

    //chrome下的显示效果
Function.prototype;//function() {}
Object.prototype;//Object {}
Number.prototype;//Number {[[PrimitiveValue]]: 0}
Boolean.prototype;//Boolean {[[PrimitiveValue]]: false}
Array.prototype;//[]
String.prototype;//String {length: 0, [[PrimitiveValue]]: ""}

  说道这里,必须提的是所有函数对象的原型对象都继承制原始对象,即fn.prototype.__proto__为原始对象(原始对象在继承属性__proto__中有定义)。这其中比较特别的是Object函数,他的原型对象就是原始对象,即Object.prototype。

    var f1 = new Function();
var f2 = Function();
var fn3 = function(){} console.log(f1.prototype.__proto__ === Object.prototype);//true
console.log(f2.prototype.__proto__ === Object.prototype);//true
console.log(f2.prototype.__proto__ === Object.prototype);//true console.log(Number.prototype.__proto__ === Object.prototype);//true
console.log(Boolean.prototype.__proto__ === Object.prototype);//true

b.继承属性__proto__


  实际上js没有继承这个东东,但是__proto__却起到了类似继承的作用。我们所知的所有的对象起源都是一个空对象,我们把这个空对象叫做原始对象。所有的对象通过__proto__回溯最终都会指向(所谓的指向类似C中的指针,这个原始对象是唯一的,整个内存中只会存在一个原始对象)这个原始对象。用下面的例子佐证

    var o = new Object();
o.__proto__;//Object {}
o.prototype;//undefined
Object.prototype;//Object {}
Object.__proto__;//function(){}
Object.__proto__.__proto__;//Object {} var f = new Function();
f.__proto__;//function(){}
f.prototype;//Object {}
Function.prototype;//function(){}
Function.__proto__;//function(){}
Function.__proto__.__proto__;//Object {}

  原始对象的__proto__属性为null,并且没有原型对象。

  所有的对象都继承自原始对象;Object比较特殊,他的原型对象也就是原始对象;所以我们往往用Object.prototype表示原始对象。

    //所有的对象都继承自原始对象
//Object比较特殊,他的原型对象也就是原始对象
//所以我们往往用Object.prototype表示原始对象
Object.prototype === o.__proto__;//true
Object.prototype === Object.__proto__.__proto__;//true
Object.prototype === Function.__proto__.__proto__;//true

  f.prototype的的值貌似也是原始对象?其实不是,我们在函数对象的原型对象这一段中不是说过吗函数对象f的原型对象实际上是函数对象的一个实例。每一个实例都是一个新的单独的对象。

new f();//Object {}

  

  所有的函数对象都继承制原始函数对象;Function比较特殊,他的原型对象也就是原始函数对象;所以我们往往用Function.prototype表示原始函数对象;而原始函数对象又继承自原始对象。

    //所有的函数对象都继承制原始函数对象,
//Function比较特殊,他的原型对象也就是原始函数对象
Function.prototype === f.__proto__
Function.prototype === Object.__proto__ ;//true
Function.prototype === Function.__proto__;//true
//所以我们往往用Function.prototype表示原始函数对象 //而原始函数对象又继承自原始对象
Function.prototype.__proto__ === Object.prototype;

  所以对象之间的继承和原型对象结构如下图(引用的别人的js object猜想图)

  看了上面的图我们还知道函数对象的原型对象的构造函数就是函数对象本身。不难理解函数对象的原型对象就是函数对象的实例了吧。

c. 原型链


  在使用New方法初始化函数的时候(详细点击查看new的深度理解)得到的新对象的__proto__属性会指向函数对象的原型对象,而函数对象的原型对象又继承至原始对象。所以呈现以下结构

    function fn(){};
var test = new fn();

  

  把这个有__proto__串起来的直到Object.prototype.__proto__为null的链叫做原型链。原型链实际上就是js中数据继承的继承链。

  如果觉得本文不错,请点击右下方【推荐】!

js基础篇——原型与原型链的详细理解的更多相关文章

  1. 前端面试题目汇总摘录(JS 基础篇)

    JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string typeof null; // o ...

  2. JS基础篇--sort()方法的用法,参数以及排序原理

    JS基础篇--sort()方法的用法,参数以及排序原理   sort() 方法用于对数组的元素进行排序,并返回数组.默认排序顺序是根据字符串Unicode码点.语法:arrayObject.sort( ...

  3. js基础篇——call/apply、arguments、undefined/null

    a.call和apply方法详解 call方法: 语法:call([thisObj[,arg1[, arg2[,   [,.argN]]]]]) 定义:调用一个对象的一个方法,以另一个对象替换当前对象 ...

  4. 前端面试题目汇总摘录(JS 基础篇 —— 2018.11.02更新)

    温故而知新,保持空杯心态 JS 基础 JavaScript 的 typeof 返回那些数据类型 object number function boolean undefined string type ...

  5. js 基础篇(点击事件轮播图的实现)

    轮播图在以后的应用中还是比较常见的,不需要多少行代码就能实现.但是在只掌握了js基础知识的情况下,怎么来用较少的而且逻辑又简单的方法来实现呢?下面来分析下几种不同的做法: 1.利用位移的方法来实现 首 ...

  6. Vue.js基础篇实战--一个ToDoList小应用

    距离开始学Vue已经过去一个多月了,总想把学到的东西柔和在一起,做点东西出来,于是有了这个Todolist小应用. 使用vuex 纯粹基础,没有用到web pack,vuex,npm,下次把它改造一下 ...

  7. JS基础:闭包和作用域链

    简介 一个定义在函数内部的函数与包含它的外部函数构成了闭包,内部函数可以访问外部函数的变量,这些变量将一直保存在内存中,直到无法再引用这个内部函数. 例如: var a = 0; function o ...

  8. js基础系列之【原型和原型链】

    声明:形成本文的出发点仅仅是个人总结记录,避免遗忘,并非详实的教程:文中引用了经过个人加工的其它作者的内容,并非原创.学海无涯 引入问题 一般我们是这样写的: (需求驱动技术,疑问驱动进步) // 构 ...

  9. JS基础篇之作用域、执行上下文、this、闭包

    前言:JS 的作用域.执行上下文.this.闭包是老生常谈的话题,也是新手比较懵懂的知识点.当然即便你作为老手,也未必真的能理解透彻这些概念. 一.作用域和执行上下文 作用域: js中的作用域是词法作 ...

随机推荐

  1. javascript检测ActiveX插件是否安装/启用

    本文主要提供在IE浏览器下检测ActiveX插件安装/启用的状态. 在一些应用开发中,需要用到一些第三方提供的ActiveX插件,如Flash插件. 为了在未安装插件的浏览器显示友好的提示,需要用到主 ...

  2. ORACLE EXP/IMP的使用详解

    导入/导出是ORACLE幸存的最古老的两个命令行工具,其实我从来不认为Exp/Imp 是一种好的备份方式,正确的说法是Exp/Imp只能是一个好的转储工具,特别是在小型数据库的转储,表空间的迁移,表的 ...

  3. 如何做到在虚拟数据库和真实数据库之间自由切换?【低调赠送:QQ高仿版GG 4.4 最新源码】

    记得以前在公司上班时,有时候白天的活没干完,我就会把工作带回家晚上加班继续做.但是,我们开发用的数据库是部署在公司局网内部的一台服务器上的,在家里是肯定连不上这台机器的.在家里没有数据库,服务端就跑不 ...

  4. js for 循环中的 变量问题。

    今日处理项目中的一个循环,本来就是一个小小的for循环,后来发现该段程序出现了问题,仔细检查代码没有发现其中的错误.无奈只好叫来了老大帮忙.通过在模版中断点调试(该方式只能自己写debugger断点) ...

  5. require、module、exports dojo中的三个特殊模块标识

    查看dojo源码过程中,发现这三个模块名并不以dojo.dijit.dojox开头,在dojo加载器中属于特殊模块名. require 这是一个上下文智能的加载器. 我们通过dojoConfig配置了 ...

  6. 如何为编程爱好者设计一款好玩的智能硬件(九)——LCD1602点阵字符型液晶显示模块驱动封装(下)

    六.温湿度传感器DHT11驱动封装(下):如何为编程爱好者设计一款好玩的智能硬件(六)——初尝试·把温湿度给收集了(下)! 七.点阵字符型液晶显示模块LCD1602驱动封装(上):如何为编程爱好者设计 ...

  7. Stealth视频教程学习笔记(第一章)

    Stealth视频教程学习笔记(第一章) 本文是对Unity官方视频教程Stealth的学习笔记.在此之前,本人整理了Stealth视频的英文字幕,并放到了优酷上.本文将分别对各个视频进行学习总结,提 ...

  8. Oracle VM VirtualBox配置文件

    Linux 虚拟机配置文件分为两处. windows下: 1.用户名/.VirtualBox/ 这里面有2个配置文件: VirtualBox.xml 和 VirtualBox.xml-prev. 后面 ...

  9. Linux之VSFTP服务

    一 .文件服务器简介 ftp:在内网和公网使用. 服务器:windows,linux 客户端:windows,linux samba:只能在内网使用(文件共享服务) 服务器:windows,linux ...

  10. Atitit 词法分析器的设计最佳实践说明attilax总结

    Atitit 词法分析器的设计最佳实践说明attilax总结 1.1. 手写的优点:代码可读,对源代码中的各种错误给出友好的提示信息,用户体验高,1 1.2. 使用状态表比较简单,dfa比较麻烦1 1 ...