深入理解javascript原型和原型链

原型

1. 什么是原型?

所有的函数都有一个特殊的属性:prototype(原型)

下面的Person.prototype就是原型(也叫显式原型),它是一个对象,我们也称它为原型对象。

function Person(name) {
    this.name = name;
}
Person.prototype.say = function () { // 通过原型添加方法
    console.log('hello ' + this.name);
}

console.log(Person.prototype);

打印出的结果是:

// 原型对象
{
	say: ƒ(),  // 原型上共享的方法,不会反复开辟存储空间,减少内存浪费。
    constructor: ƒ Person(name), 
    __proto__: {
        constructor: ƒ Object(),
        hasOwnProperty: ƒ hasOwnProperty(),
        isPrototypeOf: ƒ isPrototypeOf(),
        propertyIsEnumerable: ƒ propertyIsEnumerable(),
        toLocaleString: ƒ toLocaleString(),
        toString: ƒ toString(),
        valueOf: ƒ valueOf()
    }
}

上面这个对象,就是大家常说的原型对象
.

2. 原型的作用是什么?

原型的作用,就是共享方法。
我们通过 Person.prototype.say 可以共享方法,不会反复开辟存储空间,减少内存浪费

3. 原型中this的指向是什么?

指向实例化对象p1、p2


函数对象

  1. __proto__:任何对象( JS 中万物皆对象)都有__proto__属性(隐式原型)
  2. prototype:所有函数(仅限函数)都拥有 prototype 属性(显式原型)
  3. constructor:所有的 prototype 和 实例化对象 都有一个constructor 属性,都指向关联的构造函数本身

当我们声明一个function关键字的方法时,会为这个方法添加一个prototype属性,指向默认的原型对象,并且此prototype的constructor属性也指向方法对象。此二个属性会在创建对象时被对象的属性引用。

function Hello() {}; // 构造函数
var h = new Hello();  // 实例化对象


// 所有函数都有个prototype属性(显式原型)
console.log(Hello.prototype); // Object {}  原型对象
// 构造函数的prototype属性有个constructor属性,指向构造函数本身
console.log(Hello.prototype.constructor === Hello); // true
// 实例化对象没有prototype属性、只有函数才有prototype属性
console.log(h.prototype); // undefined


// 实例化对象的constructor属性指向构造函数本身
console.log(h.constructor === Hello); // true
// 即
console.log(h.constructor === Hello.prototype.constructor); // true 


// 所有引用类型都拥有__proto__属性(隐式原型)
console.log(h.__proto__ === Hello.prototype); // true  
// 即
console.log(h.__proto__ === h.constructor.prototype); //true
// 即
console.log(Hello.prototype === h.constructor.prototype); //true
// 即
console.log(Hello === h.constructor); // true

在这里插入图片描述
在这里插入图片描述


1. prototype

所有函数(仅限函数)都拥有 prototype 属性(显式原型)

function Person() {};

Person.prototype.sayHello = function() {
    console.log('Hello!')
}

var person1 = new Person();
var person2 = new Person();

console.log(person1.sayHello === person2.sayHello) // true,同一个方法

prototype对象用于放某同一类型实例的共享属性和方法,实质上是为了内存着想。

讲到这里,你需要知道的是,所有函数本身是Function函数的实例对象,所以Function函数中同样会有一个prototype对象放它自己实例对象的共享属性和方法。

// 实例化对象的constructor属性 指向构造函数本身
console.log(person1.constructor === Person); // true
console.log(person2.constructor === Person); // true

// Person是Function的实例对象
console.log(Person.constructor === Function); // true
console.log(Function.constructor === Function); // true

如下图:
在这里插入图片描述


2. _proto _

任何对象(JS中万物皆对象)都有__proto__属性(隐式原型),指向它的构造函数的原型对象prototype

function Person() {};

Person.prototype.sayHello = function() {
    console.log('Hello!')
}

var person1 = new Person();
var person2 = new Person();

// 所有引用类型都有__proto__属性,指向构造函数的显示原型
console.log(person1.__proto__ === Person.prototype); // true  
console.log(person2.__proto__ === Person.prototype); // true  

在这里插入图片描述

/*1、字面量方式*/
var a1 = {};
console.log(a1.constructor === Object); // true (即构造器Object)
console.log(a1.__proto__ === a1.constructor.prototype); // true
console.log(a1.__proto__ === Object.prototype); // true


/*2、构造器方式*/
var A = function (){}; 
var a2 = new A();
console.log(a2.constructor === A); // true(即构造器function A)
console.log(a2.__proto__ === a2.constructor.prototype); // true
console.log(a2.__proto__ === A.prototype); // true


/*3、Object.create()方式*/
var a1 = {a:1} 
var a2 = Object.create(a1);
console.log(a2.constructor === Object); // true  (即构造器Object)
console.log(a2.__proto__ === a1); // true 
console.log(a2.__proto__ === a2.constructor.prototype); //false

3. constructor

所有的 prototype 和 实例化对象 都有一个constructor 属性,都指向关联的构造函数本身

function Person() {};
var person1 = new Person();
var person2 = new Person();

console.log(person1.constructor === Person); // true
console.log(Person.constructor === Function); // true
console.log(Function.constructor === Function); // true

在这里插入图片描述

  1. person1 与 person2 是 Person 对象的实例,他们的 constructor 指向创建它们的构造函数,即 Person 函数;
  2. Person 是函数,但同时也是 Function 实例对象,它的 constructor 指向创建它的构造函数,即 Function 函数;
  3. Function 函数,它是JS的内置对象,它的构造函数是它自身,所以内部 constructor 属性指向自己。

所以constructor属性其实就是一个拿来保存自己构造函数引用的属性,没有其他特殊的地方。


原型链

在这里插入图片描述

var A = function () {};
var a = new A();

// 由__proto__组成的原型链
console.log(a.__proto__ === A.prototype); // true
console.log(A.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true   null表示“没有对象”,即该处不应该有值。

instanceof

instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型。

console.log([] instanceof Array); // true    =>   [].__proto__ === Array.prototype
console.log([] instanceof Object); // true   =>   Array.prototype.__proto__ === Object.prototype

console.log({} instanceof Object); //true   =>   {}.__proto__ === Object.prototype

console.log(function(){} instanceof Function); // true  =>   function(){}.__proto__ === Function.prototype
console.log(function(){} instanceof Object); // true    =>   Function.prototype.__proto__ === Object.prototype

console.log((new Number(1)) instanceof Number); // true   =>   new Number(1).__proto__ === Number.prototype
console.log((new Number(1)) instanceof Object); // true   =>   Number.prototype.__proto__ === Object.prototype

下图中由相互关联的原型组成的链状结构就是原型链,也就是蓝色的这条线
在这里插入图片描述

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype.say = function () {
    console.log('hello', this.name);
};

let student = new Person('张三', 18);

console.log(student.__proto__ === Person.prototype); // true
  1. 每个对象的__proto__都是指向它的构造函数的原型对象prototype的
    student.__proto__ === Person.prototype
    
  2. 构造函数是一个函数对象,是通过 Function构造器产生的
    Person.__proto__ === Function.prototype
    
  3. 原型对象本身是一个普通对象,而普通对象的构造函数都是Object
    Person.prototype.__proto__ === Object.prototype
    
  4. 刚刚上面说了,所有的构造器都是函数对象,函数对象都是 Function构造产生的
    Object.__proto__ === Function.prototype
    
  5. Object的原型对象也有__proto__属性指向null,null是原型链的顶端
    Object.prototype.__proto__ === null
    

.

对象之所以可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在

console.log(student.__proto__.say === Person.prototype.say); // true
console.log(student.__proto__.say === student.say); // true
console.log(student.say === Person.prototype.say); // true

.

function Parent(month){
    this.month = month;
}

var child = new Parent('Ann');

console.log(child.month); // Ann
console.log(child.father); // undefined

child中查找某个属性时,会执行下面步骤:
在这里插入图片描述
访问链路为:
在这里插入图片描述


终极图

这个图要是看懂了,原型与原型链就基本摸清了。
在这里插入图片描述

  • 11
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫老板的豆

你的鼓励将是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值