JS中原型链中的prototype与_proto_的个人理解与详细总结

本文深入浅出地解析了JavaScript中的原型链机制,包括prototype与__proto__的关系、构造函数及对象之间的联系等核心内容。

JS中原型链中的prototype与_proto_的个人理解与详细总结

一直认为原型链太过复杂,尤其看过某图后被绕晕了一整子,今天清理硬盘空间(渣电脑),偶然又看到这图,勾起了点回忆,于是索性复习一下原型链相关的内容,表达能力欠缺逻辑混乱别见怪(为了防止新人__(此处指我)__被在此绕晕,图片就放在末尾了。)

以下三点需要谨记

1.每个对象都具有一个名为__proto__的属性;

2.每个构造函数(构造函数标准为大写开头,如Function(),Object()等等JS中自带的构造函数,以及自己创建的)都具有一个名为prototype的方法(注意:既然是方法,那么就是一个对象(JS中函数同样是对象),所以prototype同样带有__proto__属性);

3.每个对象的__proto__属性指向自身构造函数的prototype;

思路扩展如下

复制代码
复制代码
 1             function Fun(){
 2             }
 3 //            我创造了一个函数Fn
 4 //            这个函数由Function生成(Function作为构造函数)
 5             var fn=new Fun()
 6 //            我创建了一个函数fn
 7 //            这个函数由Fn生成(Fn作为构造函数)
 8             
 9             
10             console.log(fn.__proto__===Fun.prototype)    //true
11 //            fn的__proto__指向其构造函数Fun的prototype
12             console.log(Fun.__proto__===Function.prototype)        //true
13 //            Fun的__proto__指向其构造函数Function的prototype
14             console.log(Function.__proto__===Function.prototype)    //true
15 //            Function的__proto__指向其构造函数Function的prototype
16 //            构造函数自身是一个函数,他是被自身构造的
17             console.log(Function.prototype.__proto__===Object.prototype)    //true
18 //            Function.prototype的__proto__指向其构造函数Object的prototype
19 //            Function.prototype是一个对象,同样是一个方法,方法是函数,所以它必须有自己的构造函数也就是Object
20             console.log(Fun.prototype.__proto__===Object.prototype)         //true
21 //             与上条相同
22 //             此处可以知道一点,所有构造函数的的prototype方法的__都指向__Object.prototype(除了....Object.prototype自身)
23             console.log(Object.__proto__===Function.prototype)        //true
24 //            Object作为一个构造函数(是一个函数对象!!函数对象!!),所以他的__proto__指向Function.prototype
25             console.log(Object.prototype.__proto__===null)        //true
26 //            Object.prototype作为一切的源头,他的__proto__是null
27 
28 //            下面是一个新的,额外的例子
29 
30             var obj={}
31 //            创建了一个obj
32             console.log(obj.__proto__===Object.prototype)        //true
33 //            obj作为一个直接以字面量创建的对象,所以obj__proto__直接指向了Object.prototype,而不需要经过Function了!!
34 
35 //            下面是根据原型链延伸的内容
36 //            还有一个上文并未提到的constructor,  constructor在原型链中,是作为对象prototypr的一个属性存在的,它指向构造函数(由于主要讲原型链,这个就没在意、);
37 
38             console.log(obj.__proto__.__proto__===null)        //true
39             console.log(obj.__proto__.constructor===Object)        //true
40             console.log(obj.__proto__.constructor.__proto__===Function.prototype)        //true
41             console.log(obj.__proto__.constructor.__proto__.__proto__===Object.prototype)    //true    
42             console.log(obj.__proto__.constructor.__proto__.__proto__.__proto__===null)        //true
43             console.log(obj.__proto__.constructor.__proto__.__proto__.constructor.__proto__===Function.prototype)    //true
44             
45             
46 //            以上,有兴趣的可以一一验证  F12搞起.
         
复制代码
复制代码

 

为了方便记忆可以得出如下结论(如有错误欢迎斧正.....)

prototype是构造函数独有的属性;

对象的__prototype__属性通常与其构造函数的prototype属性相互对应;

所有构造函数的的prototype方法的__都指向__Object.prototype(除了....Object.prototype自身);

 

需要注意的指向是

Function的__proto__指向其构造函数Function的prototype;

Object作为一个构造函数(是一个函数对象!!函数对象!!),所以他的__proto__指向Function.prototype;

Function.prototype的__proto__指向其构造函数Object的prototype;

Object.prototype的__prototype__指向null(尽头);

 

在文章结构顺便附送上俩个与原型链相关的方法....欢迎使用

1.

hasOwnProperty判断一个对象是否有名称的属性或对象,此方法无法检查该对象的原型链中是否具有该属性,该属性必须是对象本身的一个成员。 
如果该属性或者方法是该 对象自身定义的而不是器原型链中定义的 则返回true;否则返回false; 
格式如下: 
 
object.hasOwnProperty(proName);   
括号内必须要加引号,并且直接写入属性名
 
2.
 
isPrototypeOf是用来判断指定对象object1是否存在于另一个对象object2的原型链中,是则返回true,否则返回false。 
格式如下: 
object1.isPrototypeOf(object2); 
object1是一个对象的实例; 
object2是另一个将要检查其原型链的对象。 
原型链可以用来在同一个对象类型的不同实例之间共享功能。 
如果 object2 的原型链中包含object1,那么 isPrototypeOf 方法返回 true。 
如果 object2 不是一个对象或者 object1 没有出现在 object2 中的原型链中,isPrototypeOf 方法将返回 false。 
 
 

 

 

 

 

 

 

 

 

某图在这里  ps:本文是总结,加个人理解.....图是好久前留存在电脑的....忘了是在哪看到的...

 

 

 

 

 

JS对象、原型

字数664 阅读10 评论0 

Q&A:

1. OOP 指什么?有哪些特性

  • OOP,即Object Oriented Programming,面向对象编程,是计算机的一种编程架构,OOP的一条基本规则是,计算机程序由能够起到子程序作用的单个或对象组合而成。包含属性和方法的对象是类的实例,而JS中没有类的概念,而是直接使用对象实现编程任务。
  • 特性
    • 封装:能够将一个实体的信息、功能、响应都装在一个单独对象中的特性;使编程过程不必拘泥于原理,而是重在实现;
    • 继承:在不改变源程序的基础上进行扩充,原功能得以保存,并且子程序能对其进行扩展,避免编写重复代码,提高工作效率;
    • 多态:允许将子类类型的指针赋值给父类类型的指针;原生JS是弱类型语言,没有多态概念。

2. 如何通过构造函数的方式创建一个拥有属性和方法的对象?

由于函数也是对象的一种,所以继承了对象原型,可以对其添加属性和方法,构造函数也是函数,所以用自定义函数的方式,并将首字母大写以明确是构造函数即可,可以用new操作符创建函数实例验证。

function Person(name) {
      this.name = name; this.sayName = function() { console.log(this.name); } }

构造函数

3. prototype 是什么?有什么特性

  • prototype,即原型,每创建一个函数都会有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的所有实例共享的属性和方法。
  • 特性:让所有对象实例共享原型对象所包含的属性和方法:

    function Person(name) {
        this.name = name; } Person.prototype.sayName = function() { console.log(this.name); } var p1 = new Person('zhao'), p2 = new Person('kevin'); p1.sayName(); p2.sayName();

    prototype

4. 画出如下代码的原型图

    <script>
      function People(name) { this.name = name; this.sayName = function() { console.log('my name is:' + this.name); } } People.prototype.walk = function() { console.log(this.name + 'is walking'); } var p1 = new People('饥人谷'); var p2 = new People('前端'); </script>

原型图

5. 以下代码中的变量age有什么区别

      function People() {
        var age = 1;
        this.age = 10; } People.age = 20; People.prototype.age = 30;
  • var age = 1:age为局部变量;
  • this.age = 10:函数调用时,age为this指向对象的属性;
  • People.age = 20:构造函数的age变为20;
  • People.prototype.age = 30:原型添加age属性;

Coding:

1. 创建一个 Car 对象,拥有属性name、color、status;拥有方法run,stop,getStatus

function Car(name, color, status) {
      this.name = name; this.color = color; this.status = status; } Car.prototype = { constructor : Car, run: function() { this.status = 'run'; }, stop: function() { this.status = 'stop'; }, getStatus: function() { console.log(this.status); } } var car1 = new Car('BMW', 'red', 'stop');
转载自博客园'最骚的就是你'
<think>好的,我现在要回答用户关于JavaScript中原型链的作用的问题。首先,我需要回忆一下自己对原型和原型链理解,确保概念正确。然后,按照用户的要求,结构要清晰,分步骤解释,同时要遵循系统级指令中的格式要求,比如数学表达式用$...$,独立公式用$$...$$,并且用中文回答。 首先,用户可能对原型和原型链的基本概念不太清楚,需要从基础讲起。我应该先解释原型是什么,然后再说原型链,以及它们的作用。需要注意使用例子来帮助理解,同时避免技术术语过于复杂。 原型在JavaScript中是对象继承的基础。每个对象都有一个原型对象,从那里继承属性和方法。构造函数有一个prototype属性,指向实例的原型。而每个实例有一个__proto__属性,指向构造函数的prototype。这可能有点抽象,需要用具体的例子来说明。 比如,创建一个构造函数Person,然后实例化一个对象person1。Person.prototype就是person1的原型,person1.__proto__ === Person.prototype。这时候,如果person1访问一个属性,比如sayHello,而它自身没有这个属性,就会去Person.prototype上找,这就是原型链的查找机制。 接下来,原型链是如何形成的呢?比如,如果Person.prototype本身也是一个对象,它可能有自己的原型,比如Object.prototype。这样,当访问person1.toString()时,如果Person.prototype没有,就会继续向上查找Object.prototype,直到找到或者到达原型链的末端null。这个过程就是原型链的作用,实现属性和方法的继承。 然后需要提到原型链的作用,比如实现继承、共享属性和方法、节省内存等。比如,所有实例共享原型上的方法,而不是每个实例都创建一份,这样节省内存。同时,可以通过修改原型来动态添加方法,所有实例都能访问到。 可能还需要解释ES6中的class语法糖,其底层还是基于原型继承的。比如,class中的方法其实是定义在prototype上的。 需要注意是否有常见的误解需要澄清。比如,原型链的终点是null,而Object.prototype.__proto__就是null。还有,函数也是对象,所以Function.prototype也有自己的原型链。 在回答过程中,要检查是否有错误的地方。比如,构造函数.prototype的constructor属性指向构造函数本身,这点可能需要提及,但用户的问题主要关于作用和功能,所以可能不需要太深入。 最后,总结原型和原型链的作用,强调其在JavaScript面向对象编程中的重要性。确保回答结构清晰,分点说明,可能用步骤式的方式,比如分点讲解原型的作用、原型链的形成、以及它们带来的好处。 现在需要将这些思路整理成符合用户要求的结构,使用中文,正确应用LaTeX格式,比如在提到对象属性时,可能用$obj.__proto__$这样的行内公式,或者构造函数.prototype这样的写法。但根据系统指令,数学表达式需要用$...$,所以可能需要将代码相关的部分用反引号,而变量或属性名用$...$包裹,但可能用户的问题中较少涉及数学表达式,更多是代码概念。这时候可能需要判断,如果属性名如prototype或__proto__不需要用LaTeX,而如果作为例子中的变量,可能需要使用代码块或者反引号。但系统指令中提到的是行内数学表达式,比如变量、方程等需要用$...$,可能这里的变量指的是数学变量,而代码中的变量可能用反引号。需要仔细看系统指令。 系统指令中第一条说:“所有行内数学表达式(包括变量、不等式、方程等)必须使用$...$格式”,而代码相关的部分可能不属于数学表达式,所以应该用反引号。比如,在提到obj.__proto__时,应该用反引号包裹,如`obj.__proto__`,而不是$obj.__proto__$。可能我之前理解有误,需要确认。例如,用户给的例子中有$(a+b)^2$,这是数学表达式,而代码中的变量如x^2可能属于数学表达式,但代码中的属性如prototype属于代码语法,应该用反引号。所以可能需要区分,在回答中,代码相关的术语用反引号,而数学相关的用$...$。 因此,在回答中,当提到JavaScript中的属性或方法时,使用反引号,例如`prototype`,`__proto__`,而数学表达式如方程则用$...$。但用户的问题是关于JavaScript的原型,可能较少涉及数学表达式,所以可能主要使用反引号来标记代码元素,而系统指令中的数学表达式可能不适用于此,但需要遵守规则,可能用户问题中的变量如原型链相关的术语不需要用数学格式,而代码中的变量需要正确标记。不过系统指令可能更强调数学内容,而代码部分可能按常规处理,用反引号。需要再次仔细看系统指令: 系统级指令第一条:“所有行内数学表达式(包括变量、不等式、方程等)必须使用$...$格式”,而代码中的变量是否属于这里的“变量”?可能这里的变量指的是数学中的变量,而不是编程中的变量。例如,在数学表达式中的变量x用$x$,而编程中的变量如prototype用反引号。因此,在回答中,代码部分用反引号,数学表达式用$...$。例如,在提到构造函数时,用`function Person() {}`,而数学中的变量如方程中的变量用$...$。 因此,在回答中,可能较少使用数学表达式,但如果有的话要正确应用。例如,如果讨论原型链的长度或层次,可能不需要数学公式,所以可能整个回答中数学表达式较少,但需要确保符合格式。 现在,组织回答的结构: 1. 先简要介绍原型和原型链的概念。 2. 解释原型的作用,如共享属性、继承等。 3. 解释原型链的形成,通过例子说明查找机制。 4. 总结原型链的作用和重要性。 5. 可能提到ES6的class语法和原型的关系。 6. 最后举例说明,帮助理解。 需要确保每个部分都清晰,分步骤或分点,帮助用户逐步理解。同时,使用中文,避免术语堆砌,尽量口语化但准确。 现在开始写回答: 首先,原型(Prototype)是JavaScript实现继承和共享属性的核心机制。每个对象都有一个隐藏的`[[Prototype]]`属性(可通过`__proto__`访问),指向其原型对象。当访问对象属性时,如果自身不存在,则会沿原型链逐级查找,直到找到或到达终点`null`。构造函数通过`prototype`属性关联实例的原型,例如: ```javascript function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log(`Hello, ${this.name}!`); }; const person1 = new Person('Alice'); person1.sayHello(); // 输出:Hello, Alice! ``` 这里,`person1`自身没有`sayHello`方法,于是通过`person1.__proto__`(即`Person.prototype`)找到。 其次,原型链是由多个对象的`[[Prototype]]`连接而成的链式结构。例如,`Person.prototype`的原型是`Object.prototype`,因此: $$ \text{person1} \rightarrow \text{Person.prototype} \rightarrow \text{Object.prototype} \rightarrow \text{null} $$ 当调用`person1.toString()`时,JavaScript会沿此链向上查找,直到在`Object.prototype`中找到。 原型的作用包括: 1. **实现继承**:子类可共享父类的属性和方法。 2. **节省内存**:所有实例共享原型上的方法,无需重复创建。 3. **动态扩展**:修改原型后,所有实例均可立即访问新增属性。 原型链确保了JavaScript的对象体系具有灵活的继承能力,但过度依赖可能导致性能问题,需谨慎设计层次结构。</think>JavaScript 中的**原型**和**原型链**是实现继承属性共享的核心机制,下面通过结构化解释帮助你理解其作用: --- ### 一、原型(Prototype)的作用 1. **共享属性和方法** 每个构造函数(如 `Person`)都有一个 `prototype` 属性,指向一个对象。所有通过该构造函数创建的实例(如 `person1`)会**共享这个原型对象上的属性和方法**。 例如: ```javascript function Person(name) { this.name = name; } // 方法定义在原型上,所有实例共享 Person.prototype.sayHello = function() { console.log(`Hello, ${this.name}!`); }; const person1 = new Person('Alice'); const person2 = new Person('Bob'); person1.sayHello(); // Hello, Alice! person2.sayHello(); // Hello, Bob! ``` 2. **节省内存** 如果方法定义在构造函数内部,每个实例会创建独立的副本。而定义在原型上时,所有实例**共享同一份方法**,减少内存占用。 --- ### 二、原型链Prototype Chain)的作用 1. **实现继承** 当访问对象的属性时,若对象自身没有该属性,JavaScript 会通过 `__proto__` 属性(即对象的原型链)**逐级向上查找**,直到找到或到达终点 `null`。 例如: ```javascript person1.toString(); // 输出:[object Object] ``` - `person1` 自身没有 `toString` 方法。 - 查找 `Person.prototype`,也没有。 - 继续查找 `Object.prototype`(所有对象的顶层原型),找到并调用。 这形成了一条链式结构: $$ \text{person1} \rightarrow \text{Person.prototype} \rightarrow \text{Object.prototype} \rightarrow \text{null} $$ 2. **动态扩展性** 即使实例已创建,修改原型后,所有实例**仍能访问新增的属性和方法**: ```javascript Person.prototype.sayGoodbye = function() { console.log('Goodbye!'); }; person1.sayGoodbye(); // 输出:Goodbye! ``` --- ### 三、关键概念总结 1. **构造函数、实例、原型的关系** - **构造函数**:通过 `prototype` 属性关联原型。 - **实例**:通过 `__proto__` 属性指向构造函数的原型。 - **原型对象**:包含共享的属性和方法,其 `constructor` 属性指回构造函数。 ```javascript person1.__proto__ === Person.prototype; // true Person.prototype.constructor === Person; // true Object.getPrototypeOf(person1) === Person.prototype; // true(推荐写法) ``` 2. **原型链的终点** 所有原型链的顶端是 `Object.prototype`,其 `__proto__` 为 `null`: $$ \text{Object.prototype.__proto__} \rightarrow \text{null} ``` --- ### 四、ES6 中的 `class` 语法 `class` 是原型继承的语法糖,本质仍基于原型链: ```javascript class Person { constructor(name) { this.name = name; } sayHello() { /* 定义在 Person.prototype 上 */ } } ``` --- ### 五、总结:原型型链的意义 - **实现继承**:通过链式查找模拟传统面向对象语言的继承。 - **高效共享**:减少重复属性和方法的存储。 - **灵活扩展**:动态修改原型会影响所有实例。 理解型链是掌握 JavaScript 面向对象编程的关键,也能帮助规避属性遮蔽、意外覆盖等问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值