一. 普通对象与函数对象

JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象,Object 、Function等 是 JS 自带的函数对象。下面举例说明。

  1. var o1 = {};
  2. var o2 =new Object();
  3. var o3 = new f1();
  4.  
  5. function f1(){};
  6. var f2 = function(){};
  7. var f3 = new Function('str','console.log(str)');
  8.  
  9. console.log(typeof Object); //function
  10. console.log(typeof Function); //function
  11.  
  12. console.log(typeof f1); //function
  13. console.log(typeof f2); //function
  14. console.log(typeof f3); //function
  15.  
  16. console.log(typeof o1); //object
  17. console.log(typeof o2); //object
  18. console.log(typeof o3); //object
在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象(Function),其他的都是普通对象(Object)。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object也都是通过 New Function()创建的

二. 原型对象

  1. function Person(){}
  2. Person.prototype.name = 'test';
  3. Person.prototype.age = 28;
  4. Person.prototype.job = 'Software Engineer';
  5. Person.prototype.sayName = function() {
  6. alert(this.name);
  7. }
    var person = new Person();

在 JavaScript 中,每当定义一个对象(函数也是对象)时候,对象中都会包含一些预定义的属性。其中每个函数对象都有一个prototype属性,这个属性指向函数的原型对象。而原型对象他本身就是一个普通对象(没有通过 new Function() 创建的对象都是普通对象),即原型对象就是Person.prototype,如果你还是害怕它,那就把它想想成一个字母 A:var A = Person.prototype。这里要强调一点,只有函数对象才会拥有prototype属性,但是每个对象都拥有__proto__属性(null除外)

在上面我们给A添加了四个属性:name、age、job、sayName。其实它还有一个默认的属性:constructor。在默认情况下,所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype属性所在的函数(Person)。即:Person.prototype.constructor == Person。当我们创建对象var person = new Person()时,person可以继承原型对象Person.prototype的constructor属性,因此person.constructor == Person,注意person这个实例本身是没有constructor,实例的constructor是通过原型链(__proto__)获取原型对象上边的constructor。

  1. person.constructor == Person
  2. Person.prototype.constructor == Person

从这一角度,我们可以将Person.prototype理解为Person的一个实例。(但其实原型对象(Person.prototype)并不是构造函数(Person)的实例,而是构造函数的属性,而且是预定义添加的)。

  1. var A = new Person();
  2. Person.prototype = A;

但是有一个非常特别的原型对象:Function.prototype,它并不是普通对象,而是函数对象,而这个函数对象却没有prototype属性(前面所说的“每个函数对象都有一个prototype属性,这个属性指向函数的原型对象”,对Function.prototype并不适用)。

  1. function Person(){};
  2. console.log(typeof Person.prototype) //Object
  3. console.log(typeof Function.prototype) // Function,这个特殊
  4. console.log(typeof Object.prototype) // Object
  5. console.log(typeof Function.prototype.prototype) //undefined

Function.prototype为什么是函数对象呢?

  1. var A = new Function();
  2. Function.prototype = A;

上文提到过凡是通过凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。因为 A 是函数对象,所以Function.prototype是函数对象。

. __proto__

JS 在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__的内置属性,用于指向创建它的构造函数的原型对象。对象 person有一个__proto__属性,创建它的构造函数是Person,构造函数的原型对象是Person.prototype ,所以:person.__proto__ == Person.prototype

  1. Person.prototype.constructor == Person;
  2. person.__proto__ == Person.prototype;
  3. person.constructor == Person;

类似的,Person.__proto__ == Function.prototype;Person.prototype.__proto__ == Object.prototype;Object.__proto__ == Function.prototype; Object.prototype.__proto__ == null,按照上述理解 Object.prototype是普通对象,而普通对象的构造函数是Object,那么Object.prototype.__proto__ == Object.prototype,从而在原型链上形成死循环无法终止,因此定义Object.prototype.__proto__ == null,null是原型链的顶端。

不过,要明确的真正重要的一点就是,这个连接存在于实例(person)与构造函数(Person)的原型对象(Person.prototype)之间,而不是存在于实例(person)与构造函数(Person)之间

  1. var animal = function(){};
  2. var dog = function(){};
  3.  
  4. animal.price = 2000;
  5. dog.prototype = animal;
  6. var tidy = new dog();
  7. console.log(dog.price) //undefined
  8. console.log(tidy.price) // 2000

实例(tidy)和 原型对象(dog.prototype)存在一个连接。这个连接存在于实例(tidy)与构造函数的原型对象(dog.prototype)之间,而不是存在于实例(tidy)与构造函数(dog)之间。

四. 函数对象

所有函数对象的__proto__都是指向Function.prototype,它是一个空函数。

  1. Number.__proto__ === Function.prototype // true
  2. Number.constructor == Function //true
  3.  
  4. Boolean.__proto__ === Function.prototype // true
  5. Boolean.constructor == Function //true
  6.  
  7. String.__proto__ === Function.prototype // true
  8. String.constructor == Function //true
  9.  
  10. Object.__proto__ === Function.prototype // true
  11. Object.constructor == Function // true
  12.  
  13. // 所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身
  14. Function.__proto__ === Function.prototype // true
  15. Function.constructor == Function //true
  16.  
  17. Array.__proto__ === Function.prototype // true
  18. Array.constructor == Function //true
  19.  
  20. RegExp.__proto__ === Function.prototype // true
  21. RegExp.constructor == Function //true
  22.  
  23. Error.__proto__ === Function.prototype // true
  24. Error.constructor == Function //true
  25.  
  26. Date.__proto__ === Function.prototype // true
  27. Date.constructor == Function //true

所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身。所有构造器都继承了Function.prototype的属性及方法。Function.__proto__ == Function.prototype,而前面说过,Function.prototype它不是普通对象,而是函数对象,那么Function.prototype.__proto__ == ?,按照上述,Function.prototype.__proto__ == Function.prototype,但又出现了原型链上的死循环,JS一直强调万物皆对象,函数对象也是对象,给他认个祖宗,指向 Object.prototype,Object.prototype.__proto__ == null,保证原型链能够正常结束。

  1. Function.prototype.__proto__ === Object.prototype // true

特别的,Math,JSON是以普通对象形式存在的。


  1. Math.__proto__ === Object.prototype // true
  2. Math.construrctor == Object // true
  3.  
  4. JSON.__proto__ === Object.prototype // true
  5. JSON.construrctor == Object //true

四. 总结

原型和原型链是JS实现继承的一种模型。

原型链的形成是真正是靠__proto__而非prototype。

参考资料:https://www.jianshu.com/p/dee9f8b14771

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中使用使用原型(prototype)定义方法的好处

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

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

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

  7. JS中构造函数与原型对象的同名属性,实例会取哪一个

    构造函数与原型对象的同名属性,实例会取哪一个? 看了下面的过程,再回忆JS高程3里关于这部分的示意图.实例my在new的时候,本身就获得了a属性,所以my.a是1,倘若在new的时候如果没有赋予a属性 ...

  8. JS中定义对象原型的两种使用方法

    第一种: function Person() { this.username = new Array(); this.password = "123"; } Person.prot ...

  9. JS中作用域和作用域链

    1.执行环境(execution context) 执行环境定义了变量和函数有权访问的其他数据,决定了他们各自的行为.每个执行环境都有与之对应的变量对象(variable object),保存着该环境 ...

  10. JS原型和原型链

        1 var decimalDigits = 2, 2 tax = 5; 3 4 function add(x, y) { 5 return x + y; 6 } 7 8 function su ...

随机推荐

  1. Qt 入门 ---- 布局管理

    这是运行后的程序界面: 这是点击右上角"最大化"之后的程序界面: 接下来讲一下如何进行自动布局解决窗口拉伸问题. ① 原理: 在项目"设计"模式的左侧有如下两个 ...

  2. Java键盘获取数据

    java录入键盘数据,整型.浮点型.布尔型.字符串. 通过导入java.util.Scanner实现各类操作 import java.util.Scanner;//导入包 public class H ...

  3. Pb代理工具之mitmproxy

    mitmproxy 一 . mitmproxy介绍 mitmproxy 就是用于 MITM 的 proxy,MITM 即中间人攻击(Man-in-the-middle attack). 不同于 fid ...

  4. ts 学习笔记 - 类

    目录 类 类的概念 类的用法 属性和方法 类的继承 存取器 静态属性 Typescript 中的用法 抽象类 类的类型 类与接口 类实现接口 接口继承接口 接口继承类 混合类型 类 类的概念 类 (c ...

  5. SQL SERVER 作业问题(SET 选项的设置不正确: 'QUOTED_IDENTIFIER'。),以及其它定时sql执行方式探索

    在实时曲线测试平台中,需要用到实时测试数据作为依据,评估程序的可靠性.在编写sql server作业时,出现了一些问题,经过研究给予解决,供大家参考. 1.编写脚本如下: declare @i int ...

  6. Thinkphp 分页应用

    $Table = M('Table'); $count = $Table ->where()->count();        $Page = new \Think\Page($count ...

  7. Django GIS SQL注入漏洞(CVE-2020-9402)

    影响版本 Django 1.11.29之前的1.11.x版本.2.2.11之前的2.2.x版本和3.0.4之前的3.0.x版本中存在SQL注入漏洞 提示有admin.vuln.vuln2,3个页面,存 ...

  8. Linux--文件描述符、文件指针、索引节点

    Linux -- 文件描述符 文件描述符 Fd 当进程打开文件或创建新文件时,内核会返回一个文件描述符(非负整数),用来指向被打开的文件,所有执行I/O操作的系统调用(read.write)都会通过文 ...

  9. 并发编程——线程中sleep(),yield(),join(),wait(),notify(),notifyAll()区别

    前言 今天简单的讲一讲线程中sleep(),join(),yield(),wait(),notify(),notifyAll()这些方法的使用以及区别. 不过在讲这些方法之前,需要简单的介绍一下锁池和 ...

  10. 【C++】使用 libass,完成 Direct3D 11 下的字幕渲染

    前言 前段时间曾经写过一个视频播放器:https://www.cnblogs.com/judgeou/p/14746051.html . 然而这个播放器却无法显示出外挂或者内封的字幕,这里要稍微解释一 ...