js原型和原型链浅了解

本文介绍了JavaScript中的原型和原型链概念,包括prototype属性、__proto__属性、constructor以及实例与对象之间的关系。通过示例解释了如何通过原型链查找属性,并强调了Object.prototype._proto_为null,标志着原型链的结束。
摘要由CSDN通过智能技术生成

今天看了冴羽大大的JavaScript深入之从原型到原型链的文章,现在自己根据自己的理解写下笔记,方便日后翻阅。

首先创建一个对象
function Person() {};
var xiaoming = new Person();
xiaoming.name = '小明';
console.log(xiaoming.name); // 小明 
prototype(显式原型)

每一个函数都有一个prototype属性,注意:prototype是函数才会有的属性

function Person() {}
Person.prototype.name = '小明';
var xiaoming1 = new Person();
var xiaoming2 = new Person();
console.log(xiaoming1.name) // 小明
console.log(xiaoming2.name) // 小明

函数的prototype属性指向的是一个对象,这个对象就是调用该构造函数而创建的实例的原型,也就是xiaoming1和xiaoming2的原型。
原型是什么呢,就是每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型“继承”属性。

我自己的理解是:每当你创建一个对象(函数)XXX时,就会有一个XXX.prototype这样的实例原型;我们可以通过 .prototype 来访问到这个实例原型。
而这个原型的作用是可以被构造函数的实例所继承;也就是说,我们可以把一些不变的或者是公共的属性和方法,直接定义在prototype对象属性上。

可以通过下图理解构造函数和实例原型之间的关系:
构造函数和实例原型的关系图

_proto_(隐式原型)

这是每一个JavaScript对象(除了null)都具有的一个属性__proto__,这个属性会指向该对象的原型。

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

看图可能会更加清晰一点:
实例原型与构造函数的关系图

这个就很好理解啦,就是使用new创建的实例对象xiaoming可以通过__proto__来访问到实例原型

constructor

constructor属性可以指向关联的构造函数,这个属性是每一个原型都会有的属性。 需要注意的是,constructor只能指向构造函数,不能指向实例,因为一个构造函数可以生成多个实例的

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

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

总结一下:

function Person() {}
var xiaoming = new Person();
console.log(xiaoming.__proto__ === Person.prototype); // true  通过__proto__可以指向该对象的原型,所以是true
console.log(Person === Person.prototype.constructor); // true  通过原型的constructor可以指向关联的构造函数,所以是true
// 顺便学习ES5的方法,可以获得对象的原型
console.log(Object.getPrototypeOf(xiaoming) === Person.prototype) // true

以上的几个我觉得结合看图还是比较好理解的,如果不理解,就多看几遍吧~哈哈哈

实例与对象

当读取完实例的属性时,如果找不到,就会一直往上查找域对象关联的原型中的属性,一直找到最顶层为止

function Person() {}
Person.prototype.name = 'waikam';
var xiaoming = new Person();
xiaoming.name = '小明';
console.log(xiaoming.name); // 小明
delete xiaoming.name;
console.log(xiaoming.name); // waikam

这个也很明显,当我们给xiaoming实例添加了name属性的时候,打印xiaoming.name肯定就返回“小明”了。
但是当我们将xiaoming的name属性删除之后,打印xiaoming.name由于找不到name属性,所以会从xiaoming的原型也就是xiaoming.__proto__上寻找,而xiaoming.__proto__指向的是Person.prototype,所以打印xiaoming.name 的时候会返回Person.prototype的name属性,就是waikam

原型的原型

如果我们没有给构造函数的原型添加属性的话,那继续打印xiaoming.name会怎样呢?

function Person() {}
Person.prototype.name = 'waikam';
var xiaoming = new Person();
xiaoming.name = '小明';
console.log(xiaoming.name); // 小明
delete xiaoming.name;
console.log(xiaoming.name); // waikam
Object.prototype.name = 'obj';
delete Person.prototype.name; 
console.log(xiaoming.name); // obj

看上面的例子知道,原型对象是通过Object构造函数生成的,不明白的可以看图:
实例原型与构造函数的关系图

通俗点讲就是如果在孙子这里没找到就找爸爸,如果爸爸都没找到,就找爸爸的爸爸

原型链

既然如此,那Object.prototype的原型是不是又有原型呢?

function Person() {}
Person.prototype.name = 'waikam';
var xiaoming= new Person();
xiaoming.name = '小明';
console.log(xiaoming.name); // 小明
delete xiaoming.name;
console.log(xiaoming.name); // waikam
Object.prototype.name = 'obj';
delete Person.prototype.name; 
console.log(xiaoming.name); // obj
delete Object.prototype.name; 
console.log(xiaoming.name); // undefined
console.log(Object.prototype.__proto__); // null

能直接看到如果将Object原型的name属性删掉的话,你继续打印xiaoming.name会返回undefined
通过打印Object.prototype._proto_ 就会看到返回的是null,就是说Object.prototype再往上就是空了。看图:
实例原型与构造函数的关系图

这里要说明的是,图中由相互关联的原型组成的链状结构就是原型链了,就是红色的这条线

原型链就是红色的线啦,而原型一直往上找也只能找到爸爸的爸爸,毕竟不能无限套娃嘛对不对

最后再做几个例子,要填什么答案才为true

 function Person() {}
 var person1 = new Person()
 console.log(person1.constructor === ) //  true
 console.log(person1.__proto__ === ) //  true
 console.log(person1.__proto__.constructor === ) //  true
 console.log(Person.__proto__ === ) //  true
 console.log(Person.constructor === ) //  true
 console.log(Person.prototype.constructor === ) //  true
 console.log(Person.prototype === ) //  true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值