美文网首页
JavaScript原型对象与原型链

JavaScript原型对象与原型链

作者: agamgn | 来源:发表于2020-01-04 11:21 被阅读0次

一、前言

    原型和原型链是 JavaScript中不可避免需要碰到的知识点,在刚开始学习 JS 时,原型和原型链都是一个需要克服的困难。
网络上有很多讲解原型与原型链的就是放一张图,然后指来指去,很容易绕糊涂,现在我总结我对其的认识,如有错误之处,请指出。

二、前置知识

2.1构造函数

出自《你不知道的js》:在js中, 实际上并不存在所谓的'构造函数',只有对于函数的'构造调用'。

所谓的构造函数,实际上就是通过关键字new来调用的函数。

let newObj=new someFunc()  //构造调用函数

构造/new调用函数的时候做了什么new做了什么,简单说:

  • 创建一个全新的对象。
  • 这个新对象的原型(Object.getPrototypeOf(target))指向构造函数的prototype对象。
  • 该函数的this会绑定在新创建的对象上。
  • 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
  • 我们称这个新对象为构造函数的实例。

2.2普通对象和函数对象

    在JavaScript中一切皆对象,函数的本质也是一个对象,只不过函数的能力很强大罢了!ObjectFunction就是JavaScript中典型的函数对象。
如何区分函数对象和普通对象呢?

var obj={};
var func=function(){};
console.log( obj.constructor ); //f Object() { }
console.log( func.constructor ); //f Function() { }

结论:普通对象的构造函数是 Object() , 函数对象的构造函数是 Function();

三、原型

3.1什么是原型

在ES2019中prototype 的定义为

object that provides shared properties for other objects
给其它对象提供共享属性的对象。

也就是说,prototype 自己也是对象,只是被用以承担某个职能罢了
先看例子:

demo1.png
由上图可以得出以下结论
  • 函数对象的构造函数是 Function,普通对象的构造函数是 Object
  • 函数对象 有 原型 ( prototype ),普通对象 没有 原型 prototype 的

每声明一个函数,就会有一个产生一个原型,这个原型的 引用 就保存在 函数对象的 func.prototype 上面

3.1为什么要用原型

JS通过new来生成对象,但是仅靠构造函数,每次生成的对象都不一样。
有时候需要在两个对象之间共享属性,由于JS在设计之初没有类的概念,所以JS使用函数的prototype来处理这部分需要被共享的属性,通过函数的prototype来模拟类:
当创建一个函数时,JS会自动为函数添加prototype属性,值是一个有constructor的对象。
简单来说就是共享属性。

demo2.png
由demo可以看出原型是对象的共同属性,当其中一个对象修改其值时不会影响到原型上的值
这里同样也有一个疑问,为什么People1在给age赋值之后就不能访问原型上age的值,而People2没有age,却能访问原型上的age的值?这就需要引如原型链的概念了。

四、原型链

4.1认识proto属性

看一个例子: demo3.png

由demo可以得出结论:

  • __proto__是对象实例和它的构造函数之间建立的链接,它的值是:构造函数的prototype。也就是说:proto的值是它所对应的原型对象,是某个函数的prototype
  • 每一个对象,不管是函数对象或者普通对象,都会有 __proto__ 属性。
    注:这个属性现在已经不推荐使用了原因
    ,应该使用应该使用:Object.getPrototypeOf(target)(读操作)Object.setPrototypeOf(target)(写操作)、Object.create(target)(生成操作)代替。

4.2原型链是什么

看个例子:


demo5.png

如是以前的语法,从newObj查找func的原型,是这样的:

newObj.__proto__.__proto__ // 这种关系就是原型链

那么什么是原型链?用以下三句话理解:

  • 每个对象都拥有一个原型对象: newObj的原型是func.prototype。
  • 对象的原型可能也是继承其他原型对象的: func.prototype也有它的原型Object.prototype。
  • 一层一层的,以这种方式查找:在访问一个对象的某个属性/方法时,若在当前对象上找不到,则会尝试访问 newObj.__proto__, 也就是访问该对象的构造函数的原型 func.prototype,若仍找不到,会继续查找 func.prototype.__proto__,像依次查找下去。若在某一刻,找到了该属性,则会立刻返回值并停止对原型链的搜索,若找不到,则返回 undefine,这种关系就是原型链

4.2.1判断一个对象是否在另一个对象的原型链上

如果一个对象存在另一个对象的原型链上,我们可以说:它们是继承关系,关于JavaScript的继承,请参考JavaScript继承
方法有以下两种:
1.instanceof: 用于测试构造函数的prototype属性是否出现在对象的原型链中的任何位置

demo6.png
2.isPrototypeOf:测试一个对象是否存在于另一个对象的原型链上
demo7.png

4.2.2原型链的终点: Object.prototype

Object.prototype是原型链的终点,所有对象都是从它继承了方法和属性。

console.log(Object.getPrototypeOf(Object.prototype));// null

4.2.3原型链图

有以上可以引出这张图


demo10.png 下面是简图: demo4.png

看懂这图,基本上所有之前的疑问都可以解答了。

4.2.4原型链的作用

从什么是原型链的介绍中已经知道原型链的作用是什么了
属性查找,如果试图访问对象(实例instance)的某个属性,会首先在对象内部寻找该属性,直至找不到,然后才在该对象的原型(instance.prototype)里去找这个属性,以此类推

demo9.png
当你访问test的某个属性时,是这样进行查找的:
1.浏览器首先查找stringtest 本身
2.接着查找它的原型对象:String.prototype
3.最后查找String.prototype的原型对象:Object.prototype
4.一旦在原型链上找到该属性,就会立即返回该属性,停止查找。
5.原型链上的原型都没有找到的话,返回undefiend
4.2.4.1拒绝查找原型链

hasOwnProperty: 指示对象自身属性中是否具有指定的属性

let test ={ 'name': 'agamgn' }
test.hasOwnProperty('name');  // true
test.hasOwnProperty('toString'); // false test本身没查找到toString 

总结

代码地址

参考

相关文章

网友评论

      本文标题:JavaScript原型对象与原型链

      本文链接:https://www.haomeiwen.com/subject/dwzmoctx.html