原型和原型链
转博客:
https://blog.csdn.net/weixin_42614080/article/details/93413476
https://segmentfault.com/a/1190000014717972
https://blog.csdn.net/yucihent/article/details/79424506
原型和原型链
1.概念
原型:一个可以被复制(或者叫克隆)的一个类,通过复制原型可以创建一个一模一样的新对象,也可以说原型就是一个模板,在设计语言中更准确的说是一个对象模板。
原型模式是用于创建重复的对象,同时又能保证性能,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。原型模式的目的是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象,也就是说利用已有的一个原型对象,可以快速地生成和原型对象一样的新对象实例
所有引用类型(函数,数组,对象)都拥有__proto__属性(隐式原型)
所有函数拥有prototype属性(显式原型)(仅限函数)
原型对象:拥有prototype属性的对象,在定义函数时就被创建
构造函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //创建构造函数 function Word(words){ this .words = words; } Word.prototype = { alert(){ alert( this .words); } } //创建实例 var w = new Word( "hello world" ); w.print = function (){ console.log( this .words); console.log( this ); //Person对象 } w.print(); //hello world w.alert(); //hello world |
print()方法是w实例本身具有的方法,所以w.print()打印hello world;alert()不属于w实例的方法,属于构造函数的方法,w.alert()也会打印hello world,因为实例继承构造函数的方法。
实例w的隐式原型指向它构造函数的显式原型,指向的意思是恒等于
1 | w.__proto__ === Word.prototype |
当调用某种方法或查找某种属性时,首先会在自身调用和查找,如果自身并没有该属性或方法,则会去它的__proto__属性中调用查找,也就是它构造函数的prototype中调用查找。所以很好理解实例继承构造函数的方法和属性:
w本身没有alert()方法,所以会去Word()的显式原型中调用alert(),即实例继承构造函数的方法
2.原型和原型链
1 2 3 4 5 6 7 8 | Function.prototype.a = "a" ; Object.prototype.b = "b" ; function Person(){} console.log(Person); //function Person() let p = new Person(); console.log(p); //Person {} 对象 console.log(p.a); //undefined console.log(p.b); //b |
解析:
p是Person()的实例,是一个Person对象,它拥有一个属性值__proto__,并且__proto__是一个对象,包含两个属性值constructor和__proto__
1 2 | console.log(p.__proto__.constructor); //function Person(){} console.log(p.__proto__.__proto__); //对象{},拥有很多属性值 |
我们会发现p.__proto__.constructor返回的结果为构造函数本身,p.__proto__.__proto__有很多参数
我们调用constructor属性,p.___proto__.__proto__.constructor得到拥有多个参数的Object()函数,Person.prototype的隐式原型的constructor指向Object(),即Person.prototype.__proto__.constructor == Object()
从p.__proto__.constructor返回的结果为构造函数本身得到Person.prototype.constructor == Person()所以p.___proto__.__proto__== Object.prototype
所以p.b打印结果为b,p没有b属性,会一直通过__proto__向上查找,最后当查找到Object.prototype时找到,最后打印出b,向上查找过程中,得到的是Object.prototype,而不是Function.prototype,找不到a属性,所以结果为undefined,这就是原型链,通过__proto__向上进行查找,最终到null结束
1 2 | console.log(p.__proto__.__proto__.__proto__); //null console.log(Object.prototype.__proto__); //null |
大家理解刚才的过程,相信下面这些应该也都明白
1 2 3 4 5 6 7 8 | //Function function Function(){} console.log(Function); //Function() console.log(Function.prototype.constructor); //Function() console.log(Function.prototype.__proto__); //Object.prototype console.log(Function.prototype.__proto__.__proto__); //NULL console.log(Function.prototype.__proto__.constructor); //Object() console.log(Function.prototype.__proto__ === Object.prototype); //true |
4)原型的总结:
所有引用类型都有一个__proto__(隐式原型)属性,属性值是一个普通的对象
所有函数都有一个prototype(原型)属性,属性值是一个普通的对象
所有引用类型的__proto__属性指向它构造函数的prototype
5)函数的原型prototype:函数才有prototype,prototype是一个对象,指向了当前构造函数的引用地址
6)函数的原型对象__proto__:所有对象都有__proto__属性, 当用构造函数实例化(new)一个对象时,会将新对象的__proto__属性指向 构造函数的prototype
7)原型对象和函数的原型的关系
说明:
所有函数的__proto__都是指向Function的prototype
构造函数new出来的对象__proto__指向构造函数的prototype
非构造函数实例化出的对象或者对象的prototype的__proto__指向Object的prototype
Object的prototype指向null
8)所有的原型对象都会自动获得一个 constructor(构造函数)属性,这个属性(是一个指针)指向 prototype 属性所在的函数(Person)
9)实例的构造函数属性(constructor)指向构造函数 :person1.constructor == Person
10)原型对象(Person.prototype)是 构造函数(Person)的一个实例
11)原型的分类:
隐式原型(_proto_):上面说的这个原型是JavaScript中的内置属性[[prototype]],此属性继承自object对象,在脚本中没有标准的方式访问[[prototype]],但Firefox、Safari和Chrome在每个对象上都支持一个属性_proto_,隐式原型的作用是用来构成原型链,实现基于原型的继承
显示原型(prototype):每一个函数在创建之后,便会拥有一个prototype属性,这个属性指向函数的原型对象,显示原型的作用是用来实现基于原型的继承与属性的共享
12)原型的使用方式:
通过给Calculator对象的prototype属性赋值对象字面量来设定Calculator对象的原型
在赋值原型prototype的时候使用function立即执行的表达式来赋值,可以封装私有的function,通过return的形式暴露出简单的使用名称,以达到public/private的效果
原型链
1)原型链:原型链是原型对象创建过程的历史记录,当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的__proto__隐式原型上查找,即它的构造函数的prototype,如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构
2)原型设计的问题:当查找一个对象的属性时,JavaScript 会根据原型链向上遍历对象的原型,直到找到给定名称的属性为止,直到到达原型链的顶部仍然没有找到指定的属性,就会返回 undefined
也可以理解为原型链继承时查找属性的过程是先查找自身属性,当自身属性不存在时,会在原型链中逐级查找
3)hasOwnProperty 函数:可以用来检查对象自身是否含有某个属性,返回值是布尔值,当属性不存在时不会向上查找对象原型链,hasOwnProperty是 JavaScript 中唯一一个处理属性但是不查找原型链的函数
4)getOwnPropertyNames 函数:可以获取对象所有的自身属性,返回值是由对象自身属性名称组成的数组,同样不会向上查找对象原型链
5)原型链的小结:
一直往上层查找,直到到null还没有找到,则返回undefined
Object.prototype.__proto__ === null
所有从原型或更高级原型中的得到、执行的方法,其中的this在执行时,指向当前这个触发事件执行的对象
6)JavaScript的原型是为了实现对象间的联系,解决构造函数无法数据共享而引入的一个属性,而原型链是一个实现对象间联系即继承的主要方法
二、原型与原型链的常见面试题
谈谈你对原型的理解?
在 JavaScript 中,每当定义一个对象(函数也是对象)时候,对象中都会包含一些预定义的属性。其中每个函数对象都有一个prototype 属性,这个属性指向函数的原型对象,使用原型对象的好处是所有对象实例共享它所包含的属性和方法
什么是原型链?原型链解决的是什么问题?
1)原型链解决的主要是继承问题
2)每个对象拥有一个原型对象,通过 proto 指针指向其原型对象,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null(Object.proptotype.__proto__指向的是null)。这种关系被称为原型链(prototype chain),通过原型链一个对象可以拥有定义在其他对象中的属性和方法
3)构造函数 Parent、Parent.prototype 和 实例 p 的关系如下:(p.__proto__ === Parent.prototype)
在这里插入图片描述
prototype 和 proto 区别是什么?
1)prototype是构造函数的属性
2)__proto__是每个实例都有的属性,可以访问 [[prototype]] 属性
3)实例的__proto__与其构造函数的prototype指向的是同一个对象
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· DeepSeek 解答了困扰我五年的技术问题
· 为什么说在企业级应用开发中,后端往往是效率杀手?
· 用 C# 插值字符串处理器写一个 sscanf
· [翻译] 为什么 Tracebit 用 C# 开发
· 腾讯ima接入deepseek-r1,借用别人脑子用用成真了~
· Deepseek官网太卡,教你白嫖阿里云的Deepseek-R1满血版
· DeepSeek崛起:程序员“饭碗”被抢,还是职业进化新起点?
· 深度对比:PostgreSQL 和 SQL Server 在统计信息维护中的关键差异