一步一步理解js原型与原型链

100 阅读5分钟

理解js一切皆对象

对象——若干属性的集合。 在js中一切(引用类型)都是对象,对象是属性的集合。但对象也是有区别的。分为普通对象和函数对象,Object 、Function 是 JS 自带的函数对象。

var o1 = {}; 
var o2 =new Object();
var o3 = new f1();

function f1(){}; 
var f2 = function(){};
var f3 = new Function('str','console.log(str)');

console.log(typeof Object); //function 
console.log(typeof Function); //function  

console.log(typeof f1); //function 
console.log(typeof f2); //function 
console.log(typeof f3); //function   

console.log(typeof o1); //object 
console.log(typeof o2); //object 
console.log(typeof o3); //object

在上面的例子中 o1 o2 o3 为普通对象,f1 f2 f3 为函数对象。怎么区分,其实很简单,凡是通过 new Function() 创建的对象都是函数对象,其他的都是普通对象。f1,f2,归根结底都是通过 new Function()的方式进行创建的。Function Object 也都是通过 New Function()创建的

理解new 构造函数

ECMAScript 中提供了构造函数来创建新对象。但构造函数本身就是一个函数,与普通函数没有任何区别,只不过为了区分,一般将其首字母大写,但这并不是必须的。

函数被 new 关键字调用时就是构造函数。 不被new 关键字调用时就是普通函数执行


function f(name) {
    console.log("execute");
    this.name = name;
}

var k = new f("k"); // execute
console.log(k); // {name: "k"}
var h = f("h"); // execute
console.log(h); // undefined
  • 首字母是否大写并不影响函数 f 作为构造函数使用,
  • 不使用 new 调用函数就是普通函数,直接执行内部代码,使用 new,函数的角色就成为了构造函数,创建一个对象并返回。

理解new 关键字的内部实现机制:

new constructor()

  • 创建一个新对象;
  • 将构造函数的作用域赋值给新对象;
  • 执行构造函数中的代码;
  • 返回新对象
var obj = {}; // 创建一个空对象
obj.__proto__ = constructor.prototype; // 添加__proto__属性,并指向构造函数的 prototype 属性。
constructor.call(this); // 绑定this
return obj;

理解prototype

prototype是函数对象所拥有的一个属性,而prototype的本质是一个对象,称为原型对象。在原型对象prototype中有许多属性,一个属性叫constructor(见下文)指向这个函数本身。每个函数都有一个prototype

屏幕截图 2022-02-20 164212.png

理解constructor

在javascript语言中,constructor属性是专门为function而设计的,它存在于每一个function的prototype属性中,这个constructor保存了指向function的一个引用。指向函数本身

function Person(){}
Person.prototype.constructor===Person //true

理解__proto__

每个对象都有一个__proto__。指向创建该对象的函数的prototype。如

function Person(){}
var p1=new Person()
p1.__proto__===Person.prototype //true

理解实习与原型的关系

理解原型链

JavaScript 中描述了原型链的概念,并将原型链作为实现继承的主要方法。其基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。简单回顾一下构造函数、原型和实例的关系:每个构造函数都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针(constructor),而实例都包含一个指向原型对象的内部指针(proto)。JavaScript对象通过__proto__ 指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条, 即原型链。

复习巩固

image.png
首先复习几个重要的概念

  1. 函数也不是从石头缝里蹦出来的,函数也是被创建出来的。谁创建了函数呢?——Function——注意这个大写的“F"
  2. 每个对象都有一个__proto__。指向创建该对象的函数的prototype。
  3. prototype是函数对象所拥有的一个属性,而prototype的本质是一个对象,称为原型对象。
  4. 函数的prototype中有一个constructor属性指向函数自己。
  5. Object 、Function 是 JS 自带的函数对象。 接着我们对上面10条线路进行一个分析。学习原型与原型链后可以试试自己画个图,在浏览器控制台验证你的想法。
  1. 每个函数都有自己的prototype,如函数 person的prototype指向 Person.prototype
  2. 每个prototype原型对象中有个属性constructor指针指向函数自己。 Person.prototype.constructor===Person
  3. prototype原型对象本质上的一个对象,是由function Object函数生成的,所以Person.prototype._proto_指向的是创建该对象的函数的prototype,即Object.prototype。Person.prototype.proto===Object.prototype
  4. (理解function Function也是一个函数很关键)Function也是一个函数,函数是一种对象,也有__proto__属性。既然是函数,那么它一定是被Function创建。所以——Function是被自身创建的。所以它的__proto__指向了自身的Prototype。Function.proto===Function.Prototype。
  5. 每个prototype原型对象中有个属性constructor指针指向函数自己。Function.prototype.constructor===Function
  6. 每个函数都有自己的prototype,如函数 Function的prototype指向 Function.prototype
  7. function Object是个函数,函数也是一个对象,也有__proto__属性。既然是函数,那么它一定是被Function创建。每个对象都有一个__proto__。指向创建该对象的函数的prototype。所以object.proto===Function.prototype。
  8. 每个prototype原型对象中有个属性constructor指针指向函数自己。Object.prototype.constructor===object
  9. 每个函数都有自己的prototype。
  10. Obeject.prototype位于原型链顶端,其__proto__为null。Object.prototype.proto===null
function Person(){}

var person1=new Person();

console.log("Person.prototype.constructor===Person :",Person.prototype.constructor===Person)//true

console.log("Person.prototype._proto_===Object.prototype :",Person.prototype.__proto__===Object.prototype)//true

console.log("Function.__proto__===Function.Prototype :",Function.__proto__===Function.prototype)//true

console.log("Function.prototype.constructor===Function :",Function.prototype.constructor===Function)//true

console.log("Object.__proto__===Function.prototype :",Object.__proto__===Function.prototype)//true

console.log("Object.prototype.constructor===object :",Object.prototype.constructor===Object)//true

console.log("Object.prototype.__proto__===null :",Object.prototype.__proto__===null)//true

原型链题目

  1. person1.__proto__ 是什么?
  2. Person.__proto__ 是什么?
  3. Person.prototype.__proto__ 是什么?
  4. Object.__proto__ 是什么?
  5. Object.prototype__proto__ 是什么?

答案:
第一题:
因为 person1.__proto__ === person1 的构造函数.prototype
因为 person1的构造函数 === Person
所以 person1.__proto__ === Person.prototype

第二题:
因为 Person.__proto__ === Person的构造函数.prototype
因为Person的本质是一个函数Person的构造函数 === Function
所以 Person.__proto__ === Function.prototype

第三题:
Person.prototype 是一个普通对象,我们无需关注它有哪些属性,只要记住它是一个普通对象。
因为一个普通对象的构造函数 === Object
所以 Person.prototype.__proto__ === Object.prototype

第四题,参照第二题,因为 Person 和 Object 一样都是构造函数

第五题:
Object.prototype 对象也有proto属性,但它比较特殊,为 null 。因为 null 处于原型链的顶端,这个只能记住。
Object.prototype.__proto__ === null

本文引用

www.cnblogs.com/wangfupeng1…
作者 王福朋
www.jianshu.com/p/dee9f8b14…
作者 Yi灌可乐