二,3分钟快速理解js中的【原型 / 原型链】。

二,3分钟快速理解js中的【原型 / 原型链】。

原型/原型链前端面试高频出现,极为重要!!!

相信大名鼎鼎的JS三座大山【原型/原型链】,【闭包/作用域】,【异步/单线程】在前端童鞋中是无人不知无人不晓了。曾经学习JS的时候看了N多篇相关的文章,根本记不住什么是原型/原型链,一大堆乱七八糟的东西扰乱视线。今天写一下自己对原型/原型链的理解,如有不对之处,还请各位童鞋指出。

要理解JS中的【原型/原型链】不能从字面意思去理解,不然很容易迷糊。咱们先不要管概念,直接讲原理;
回顾一下上一篇中写到了JS的【变量类型】,回顾一下js的变量类型分类【值类型】和【引用类型

(1)值类型:字符串(String)、数字(Number)、布尔值(Boolean)、Null、Undefined

(2)引用类型:对象(Object)、数组(Array)、函数(Function)

值类型引用类型有什么区别?

1).每一个值类型都有一个独立的内存区域保存自己的值,调用它的时候调用的是他的值,而引用类型调用的是内存中的地址。

下面看例子1:
var a = 1, b = a;
console.log(b) // 1
b = 2; console.log(a) // 1改变b的值再打印a的值我们看看
这里不管怎么改变b的内容,a永远不会被b影响,a的值永远是1;因为a和b都有一个独立的内存区域保存自己的值,调用它的时候调用的是他的值。

再看例子2:
var a = {x:1,y:2}, b = a;声明一个变量a,再声明一个变量b赋值为a
console.log(b); // {x:1,y:2}打印b,发现b和a的内容一样
console.log(a===b) // true确认一下,a绝对等于b
b.x = 3, b.y = 4; console.log(a);改变b的值,再打印a,奇迹出现了
console.log(a); // {x:3,y:4}
我们改变b的值这时候a竟然也改变了?什么情况?
之前提到了引用类型调用的是内存中的地址而不是调用它的值,所以你第一次声明一个引用类型的时候(声明a)会给a开辟一块内存空间用来存放a,再声明b=a的时候不会再次开辟一块内存空间,而是直接把变量b指向到了存放a的内存空间中,此时a和b公用一块内存空间;没错,JS因为一些设计上的原因它就是这样的机制。
这里把a换成数组或者函数,只要属于引用类型都是这种机制。

当然还有一个误区:
var a = {x:1,y:2}, b = a;
b = {x:3,y:4};
console.log(a) // {x:1,y:2}
为什么这里a的值就不会改变了呢?因为你没有去改变b的值,而是给b重新赋值。这时候相当于给b重新开辟了一块内存空间而不是改变b和a公用的内存空间里的内容。这就是值类型引用类型区别之一

那么他们还有什么区别呢?有!
所有的引用类型都有一个__proto__属性(proto前后各两个下划线),我们称之为【隐式原型

从上图可以看出,我们声明一个变量a为一个对象(引用类型)的时候它会多出一个属性__proto__

再看第二张图
在这里插入图片描述
我们声明了对象,数组和函数,发现函数有一个prototype属性而对象和数组没有。因为所有的函数都有一个prototype属性,我们称之为【显式原型】;这里函数也是引用类型,所以函数既有显式原型又有隐式原型。这就叫做原型;那么什么是原型链呢?看第三张图
在这里插入图片描述
我们写一个构造函数P,然后在P的显式原型上设置一个属性name,值为字符串’czj’
然后new一个构造函数P的实例赋值给变量a,再打印一个a的name属性,结果是’czj’。很奇怪对不对,我们明明没有设置a的name属性。这是为什么呢?这里涉及到两个JS的设计规则

一.)就是一个函数的隐式原型__proto__指向它构造函数的显式原型prototype
所以a.__proto__ === P.prototype // true

二.)当JS在一个函数中找一个属性或者方法没有找到的时候就会去那个函数的原型中去寻找。
当我们打印a.name的时候a本身没有name属性所以会去a.__proto__属性中去寻找,又因为函数的隐式原型__proto__绝对等于它构造函数的显式原型prototype所以a.__proto__ === P.prototype,而我们之前在P.prototype中设置过name属性,所以a.name === 'czj'。就这样函数a有原型P,那么P呢?P.__proto__ === Function.prototype // trueP的构造函数其实是Function。就这样函数a的构造函数是P,P的构造函数是Function对象new出来的,而他们又各自都有各自的原型,那么就形成了一条原型链。这就叫做原型链!

另外提一点,值得注意的是原型链并不是无限存在下去的,原型链的顶端是Object.prototype
其实还有很多如instanceof, constructor跟原型链的关系没有写,这个留到以后的文章中再说吧。

下一篇写一下【闭包/作用域

  • 8
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 原型是每个 JavaScript 对象都有的一个内部属性,它指向另一个对象,该对象包含共享属性和方法。原型链是由原型对象组成的链,它允许对象继承另一个对象的属性和方法。当我们访问一个对象的属性或方法时,如果该对象本身没有该属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到该属性或方法或者到达原型链的顶端。 ### 回答2: 在JavaScript,每个对象都有一个原型对象,它是用来共享属性和方法的。当我们访问一个对象的属性或方法时,如果对象本身没有这个属性或方法,JavaScript会沿着原型链依次查找,直到找到该属性或方法或者找不到为止。 原型对象是通过构造函数创建的,可以将构造函数的原型属性称为原型对象。当我们使用构造函数创建一个对象时,这个对象会自动继承构造函数的原型对象上的属性和方法。 原型链是由一系列对象的原型对象组成的链状结构。当我们访问一个对象的属性或方法时,JavaScript会先查找对象本身是否有该属性或方法,若没有则会去它的原型对象查找,若原型对象仍然没有,则继续查找原型对象的原型对象,直到查找到顶层的Object.prototype对象为止。 当一个函数被定义时,它会自动创建一个原型对象,并且这个原型对象会默认添加一个constructor属性,该属性指向函数本身。在使用构造函数创建对象时,新创建的对象会继承构造函数的原型对象上的所有属性和方法。 通过原型原型链的机制,我们可以实现对象之间的属性和方法的共享,避免重复创建和占用内存。它使得JavaScript的对象可以实现简单的继承,并且可以方便地进行属性和方法的扩展和修改。 总结起来,原型原型链是JavaScript实现面向对象特性的重要概念。通过原型链的查找机制,我们可以实现属性和方法的继承和共享,使得代码更加简洁和高效。 ### 回答3: 在JavaScript,每个对象都有一个原型(prototype),原型是一个对象,它包含了对象的属性和方法。原型可以被其他对象所共享,这样它们就可以访问到相同的属性和方法。 当我们访问一个对象的属性或方法时,JavaScript引擎会先查找该对象本身是否拥有这个属性或方法,如果没有找到,则会继续查找该对象的原型,即原型链的下一个对象,以此类推,直到找到该属性或方法,或者查找到达原型链的末尾。 原型链是由原型组成的,即一个对象的原型是另一个对象,而这个对象又有自己的原型,依此类推,形成了一个链条。可以把原型链看作是一种对象之间的继承关系。 当我们创建一个对象时,它会有一个隐藏的属性`__proto__`,指向该对象的原型。我们可以通过`Object.create()`方法来显式地指定对象的原型。如果我们尝试访问对象的一个属性或方法,而该对象本身没有这个属性或方法,JavaScript引擎会自动去原型链上查找,直到找到或者返回`undefined`。 原型原型链的概念在JavaScript是非常重要的,它们使得对象可以通过继承的方式共享属性和方法,提高了代码的可复用性和扩展性。同时,原型链也是JavaScript实现对象的继承机制的基础。我们可以通过修改原型链上的对象,来为现有对象增加属性和方法,或者扩展对象的行为。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值