花费 3 天时间,整理的原型、原型链,希望对你有用

2018.05.13

最近,再次研究原型。之前对原型的理解,还值停留在记忆的层面,所以这次深入了解这里面的奥秘。注意:以下的文章内容,是针对 ES5以及ES5之前的js;因为 ES6已经有类这个概念了。

第一部分:导入 – js 中的对象

王福鹏的博客,js中的对象

第二部分:js中的 function类型

ES5以及ES5之前, js 中没有类的概念,所以 js的面向对象与 java的面向对象是不一样的。

1:类与实例的概念

  • 类:类是对象的类型模板,例如,定义Student类来表示学生,类本身是一种类型,Student表示学生类型,但不表示任何具体的某个学生;
  • 实例:实例是根据类创建的对象,例如,根据Student类可以创建出xiaoming、xiaohong、xiaojun等多个实例,每个实例表示一个具体的学生,他们全都属于Student类型。

2:js 中函数的功能?

  • 作为一般的函数调用
  • 作为构造函数(此时函数名首字母要大写),也就是 new

3:构造函数中 new的作用?或者说 new 做了哪些事情?

let p = {}
p.__proto__ = Person.prototype
Person.call(p)
  • 第一行:创建一个空对象 p
  • 第二行:将这个空对象 p 的proto 属性指向构造函数 Person的prototype属性
  • 第三行:将 Person构造函数的 this指针替换成 p ,并调用构造函数 Person。于是 p 也有了构造函数Person的属性。

链接:js中的new()到底做了些什么?

4:函数的 prototype属性

js中,函数具有 prototype属性、proto属性。值得注意的是:prototype属性对函数,是不可见的,也就是说,函数不会查找 prototype中的属性和方法。例如:

function Person (name,color) {
    this.name = name;
    this.color = color;
}
Person.prototype.hobby = '妹子'
console.log(Person.hobby); // undefined

那么,prototype属性有什么用呢?其实 prototype属性的主要作用就是继承。也就是说,prototype属性中定义的方法和属性是留给“后代”使用的,因此,“后代”就可以访问prototype属性中的方法和属性。对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。 阮一峰谈论js的原型、继承

第三部分:基本概念与备注

基本概念

  • 原型:每个函数都有一个prototype属性,这个属性就是原型。参见:《js高程147页》或链接王福鹏博客
    (因为,我把原型和原型对象搞混了,花了很长时间,才彻底搞懂。如果对原型和原型对象懂的话,不用看这个注释。) 函数的prototype属性,是一个指针,指向一个对象,这个对象就是原型对象。通过这个属性,可以直接访问到这个对象,所以原型和原型对象是同一个。所以你可以看到,原型有时候也称为原型对象。
  • 构造函数:用于创建对象的函数,通过new关键字生成对象。函数名一般首字母大写的。示例代码一中的 Person 就是构造函数。
  • 实例对象:由构造函数实例化的对象,就是实例对象。示例代码一中的 p 就是实例对象。
示例代码一:
funtion Person (name,color) {
    this.name = name;
    this.color = color;
}
let p = new Person('李富贵','黄色')

备注:

  • 函数是对象
  • js中的对象,具有proto属性
  • 函数具有prototype属性,由于函数也是对象,因此函数也有 proto 属性。因此函数具有prototype属性和 proto 属性。
    对于普通函数,它的prototype属性基本无用,所以这篇文章侧重的是构造函数。参考链接prototype 对象,by阮一峰

第四部分:原型链探索

1:构造函数、实例对象、原型对象之间的关系图

![image](https://s1.ax1x.com/2018/05/15/CrqCOU.png)

2:寻找 Person构造函数的原型

由于构造函数也是对象,也有prot属性,所以构造函数也有原型。

只要根据 “对象.__proto__=== 构造函数.prototype” 这个公式,就可以找到答案。 函数也不是从石头缝里蹦出来的,函数也是被创建出来的。谁创建了函数呢?——Function——注意这个大写的“F”。 且看如下代码。
function fn(x, y) {
    return x + y
}
console.log(fn(10, 20));// 30

let fn1 = new Function('x', 'y', 'return x + y;') 
console.log(fn1(10, 20)); // 30
以上代码中,第一种方式是比较传统的函数创建方式,第二种是用new Functoin创建。 首先根本不推荐用第二种方式。这里只是向大家演示,函数是被Function创建的。 记住:所有的函数都是被 Function 创建的。所以 Person构造函数的__proto__指向 Function.prototype [参考链接:王福朋的博客](http://www.cnblogs.com/wangfupeng1988/p/3979290.html) ![image](https://s1.ax1x.com/2018/05/15/CrqkTJ.png)

3:寻找 Person.prototype的原型

因为js中的所有的对象都是由 Object 这个对象创建的。而 Person.prototype 也是对象,所以 Person.__proto__指向 Object.prototype ![image](https://s1.ax1x.com/2018/05/15/CrqZf1.png)

4:寻找 Function的原型

其实稍微想一下就明白了。Function也是一个函数,函数是一种对象,也有proto属性。既然是函数,那么它一定是被Function创建。所以Function是被自身创建的。所以它的proto指向了自身的Prototype。
注意:这里比较特殊。Function.proto = Function.prototype
image

5:寻找 Function.prototype 的原型

因为js中所有对象都是由 Object 这个对象创建的 。而 Function.prototype 也是对象,所以 Function.proto 指向 Object.prototype
image

6:寻找 Object.prototype 的原型

  • 特列:Object.prototype确实一个特例——它的proto指向的是null,切记切记!
    image

7:js 中的内建对象的原型

Object,Array,String,Date,RegExp 都是js的内建对象。它们的原型是谁呢?

console.log(typeof Object);//function
console.log(typeof Number);//function
console.log(typeof Array);//function
console.log(typeof String);//function
console.log(typeof Date);//function
console.log(typeof RegExp);//function

console.log(typeof Function);//function

我们可以通过内建对象创建其他对象。如:
let obj = new Object()
let arr = new Array()
这里的方式是不是跟 let p = new Person() 好像呀。 

可以看到 js中的内建对象,都是函数。内建对象应该是由 Function 实例化的,那么内建对象的proto 指向 Function 的prototype。我们来验证下:

Object.__proto__ === Function.prototype;//true
Number.__proto__ === Function.prototype;//true
Array.__proto__ === Function.prototype;//true
String.__proto__ === Function.prototype;//true
Date.__proto__ === Function.prototype;//true
RegExp.__proto__ === Function.prototype;//true

这里为了方便画图,就以 Object作为内建对象的代表。
注意:这里比较特殊。Object.proto = Function.prototype
image

第五部分:给原型链加上 constructor 属性。

  • 原型(对象)上有一个 constructor 属性,指向对应的构造函数。
    image

  • 网上的原型链的常见图片
    image

原型链:

  • 原型链:每一个对象都有自己的原型对象,原型对象本身也是对象,原型对象也有自己的原型对象,这样就形成了一个链式结构,叫做原型链。

可以看到:原型链的实质,就是proto属性

第六部分:参考链接:

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_37219302/article/details/80331061
文章标签: js原型
个人分类: javascript web前端
上一篇chrome手机端调试web页面(前端项目)
下一篇花 2 天时间整理的,---- 浏览器的渲染原理
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭