js|原型和原型链的理解🎁🎁

248 阅读5分钟

一、原型

js是使用构造函数来创建一个新的对象的,每一个构造函数内部都有一个prototype属性,属性值是一个对象,这个对象包含了构造函数的所有实例共享的属性和方法。

使用构造函数新建的对象内部有一个指针,指向构造函数的prototype属性对应的值,在ES5中这个指针被称作原型。

现在的浏览器实现了__proto__来访问这个属性,但是他不是规范的,ES6新增了Object.getPrototypeOf()方法获取对象的原型

二、原型链

访问一个对象属性的时候,如果没有找到就会去他原型上找,原型对象又有自己的原型,就这样一直找下去,也就是原型链的概念。

原型链的顶层是null

三、图示解释

image (4).png

在了解原型和原型链的关系之前,我们先梳理一下实例、构造函数、原型对象这几者存在的关系

四、构造对象的方法

// 第一种:字面量
let obj = {
    name: 'tom1'
}
let obj = new Object({ name: 'tom2' })
// 第二种:构造函数
function M(name) {
    this.name = name;
}
let obj = new M('tom3');
//第三种:方法
let obj = Object.create('tom4');

五、构造函数和原型对象的关系

每一个构造函数都有一个原型对象

function M(name) {
    this.name = name;
}
let obj = new M('tom3');
console.log(M.prototype); // {}

原型对象通过constructor指针指向构造函数

function M(name) {
    this.name = name;
}
let obj = new M('tom3');
console.log(M.prototype.constructor === M); // true

总结

涉及到构造函数和原型对象的就是:构造函数、原型对象、prototype、constructor

六、原型对象和实例的关系

实例通过内部的__proto__指向原型对象,实例和构造函数指向的是同一个原型对象

function M(name) {
    this.name = name;
}
let obj = new M('tom3');
console.log(obj.__proto__);//{}
console.log(obj.__proto__ === M.prototype); // true

总结

涉及到实例和原型对象的就是:实例、原型对象、__proto__

任何一个对象都有__proto__属性,一个对象在创建之后,指针__proto__就指向了它的原型,对象的属性和方法可以从原型中继承。

实例对象可以访问原型对象的所有属性和方法

所有的实例对象共享同一个原型对象

七、构造函数和实例的关系

通过new一个构造函数得到对应的实例

// 通过new--->obj是构造函数M的实例
function M(name) {
    this.name = name;
}
let obj = new M('tom3');

八、什么是原型链

解释1:

当一个对象的属性不存在时,就去他的原型上找,如果原型上也没有,就会去原型的原型上找,最后会到Object.prototype,Object.prototype的原型是null,如果没有找到返回undefined,如果在某原型处找到,返回值。这条寻找的链就是原型链。

解释2:

只要是对象就有原型,原型也是对象,因此只要定义了一个对象,就可以找到它的原型,如此反复,就可以构成一个对象序列,这就是原型链。

解释3:

由于__proto_是任何对象都有的属性,而js中一切皆对象,所以就会形成一条__proto__连起来的链条,当递归访问___proto__一定会到尽头,最终是null

image (5).png

九、关于Function 和Object

Function instanceof Object;//true
Object instanceof Function;//true
//因为:
Function.prototype.__proto__ === Object.prototype;//true object是顶层对象
Object.__proto__ === Function.prototype;//true
Function.__proto__ === Function.prototype; // true
  1. 一切对象继承Object对象,Object对象继承根对象null
  2. 一切函数对象(包括Object)都继承Function对象
  3. Object对象直接继承Function对象
  4. Function对象继承自己,最终继承Obejct对象

十、分析Function 和Object的关系

把Function当对象

一切对象继承Object对象,Object对象继承根对象null

例如定义let num= 1;

num的原型链: num---->Number.prototype--->Object.prototype--->null

例如定义一个let fn = function (){}

fn的原型链: fn--->Function.prototype--->Object.prototype--->null

把Object当函数

一切函数对象(包括Object)都继承Function对象

函数对象包括Function、Object、Array、String、Number,正则对象RegExp、Date对象

Function的原型链:

Function--->Funciton.prototype--->Object.prototype--->null

Object的原型链:

Obejct--->Function.prototype--->Object.prototype--->null

可以说Object和Function是互相继承的关系

object是顶层对象,Function是顶层构造函数

image (6).png

Function.constructor = Function
Funciton.prototype = 一个匿名函数
Funciton.prototype.__proto__ = Object.prototype
Object.conctructor = Function
Object.prototype = null
Object.__proto__ = Function.prototype

十一、prototype

每一个函数都有一个显式的属性prototype(显示原型)

var fn = function () { }
console.log(fn.prototype); // {}

image (7).png

十二、__proto__

每一个引用类型(数组、函数、对象)都有一个隐式的属性__proto__,(隐式原型)属性值是一个普通的值

var obj = {} // 对象
var arr = [] // 数组
var fn = function () { } // 函数
console.log(obj.__proto__); // [Object: null prototype] {}
console.log(arr.__proto__); // Object(0) []
console.log(fn.__proto__); // {}

十三、__proto__和prototype

实例对象的隐式原型__proto__指向它的构造函数的显示原型prototype

var obj = {}
var arr = []
var fn = function () { }
console.log(obj.__proto__ === Object.prototype); // true
console.log(arr.__proto__ === Array.prototype); // true
console.log(fn.__proto__ === Function.prototype); // true

image (11).png

十四、constructor

每一个原型(Person.prototype)都有一个constructor属性

function Person (){};
console.log(Person.prototype.constructor === Person); // true
function Person() { };
var person = new Person();
console.log(Person.prototype.constructor === Person); // true
console.log(person.__proto__.constructor === Person); // true 
console.log(person.__proto__ === Person.prototype); // true

image (8).png

十五、原型的原型

原型也是一个对象,我们可以用最原始的方式创建它

var  obj = new Object();
obj.name = 'kin';
console.log(obj.name); // kin

其实原型对象就是通过Object的构造函数生成的,实例的__proto__指向构造函数的prototype

image (9).png

十六、Object.prototype

Object.prototype.__proto__ === null  // true
Object.prototype.__proto__ 的值为 nullObject.prototype 没有原型,其实表达了一个意思。

原型链

构造函数、原型、实例之间的关系 每一个构造函数都有一个原型对象,原型对象包含指向构造函数的指针 实例包含指向原型对象的内部指针(__proto__

如果我们让原型对象等于另一个对象的实例,此时的原型对象(Person)将包含指向另一个原型(Object)的指针(__proto__) 另一个原型对象又是另一个对象的实例,那么依然会存在上述的关系,层层递进,就会形成原型链

image (10).png

参考👀

blog.csdn.net/m0_37585915…

github.com/mqyqingfeng…

www.cnblogs.com/libin-1/p/5…