美文网首页
原型与原型链相关

原型与原型链相关

作者: 你喜欢吃青椒吗_c744 | 来源:发表于2019-08-02 11:51 被阅读0次

前言

最近在整理原生JS的相关知识,发现关于原型和原型链涉及的知识对理解JS有很大的帮助。遂分享一下。

构造函数

所谓构造函数,就是提供了一个生成对象的模板并描述对象的基本结构的函数。一个构造函数,可以生成多个对象,每个对象都有相同的结构。总的来说,构造函数就是对象的模板,对象就是构造函数的实例。

  • 构造函数的首字母必须大写,用来区分于普通函数
  • 内部使用的this对象,来指向即将要生成的实例对象
  • 使用New来生成实例对象

构造函数的缺点

所有的实例对象都可以继承构造函数中的属性和方法。但是,同一个对象实例之间,无法共享属性

function Person(name,height){
 this.name=name;
 this.height=height;
 this.hobby=function(){
 return 'watching movies';
}
 }
var boy=new Person('keith',180);
 var girl=new Person('rascal',153);
 console.log(boy.name); //'keith'
 console.log(girl.name); //'rascal'
 console.log(boy.hobby===girl.hobby); //false

上面代码中,一个构造函数Person生成了两个对象实例boy和girl,并且有两个属性和一个方法。但是,它们的hobby方法是不一样的。也就是说,每当你使用new来调用构造函数放回一个对象实例的时候,都会创建一个hobby方法。这既没有必要,又浪费资源,完全可以被两个对象实例共享。
所以,构造函数的缺点就是:同一个构造函数的对象实例之间无法共享属性或方法

prototype解决这个问题

为了解决构造函数的对象实例之间无法共享属性的缺点,js提供了prototype属性。

js中每个数据类型都是对象(除了null和undefined),而每个对象都继承自另外一个对象,后者称为“原型”(prototype)对象,只有null除外,它没有自己的原型对象。

原型对象上的所有属性和方法,都会被对象实例所共享。

function Person(name,height){
this.name=name;
this.height=height;
}
Person.prototype.hobby=function(){
return 'watching movies';
}
var boy=new Person('keith',180);
var girl=new Person('rascal',153);
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby); //true
//将hobby方法放在原型对象上,那么两个实例对象都共享着同一个方法。

上面代码中,当修改了原型对象的hobby方法之后,两个对象实例都发生了变化。这是因为对象实例其实是没有hobby方法,都是读取原型对象的hobby方法。也就是说,当某个对象实例没有该属性和方法时,就会到原型对象上去查找。如果实例对象自身有某个属性或方法,就不会去原型对象上查找

boy.hobby=function(){
 return 'play basketball';
 }
 console.log(boy.hobby()); //'play basketball'
 console.log(girl.hobby()); //'swimming'
//上面代码中,boy对象实例的hobby方法修改时,就不会在继承原型对象上的hobby方法了。不过girl仍然会继承原型对象的方法。

总结:

  • 原型对象的作用,就是定义所有对象实例所共享的属性和方法
  • prototype,对于构造函数来说,它是一个属性;对于对象实例来说,它是一个原型对象。

原型链

对象的属性和方法,有可能是定义在自身,也有可能是定义在它的原型对象。由于原型对象本身对于对象实例来说也是对象,它也有自己的原型,所以形成了一条原型链(prototype chain)。

比如,a对象是b对象的原型,b对象是c对象的原型,
以此类推。所有一切的对象的原型顶端,都是Object.prototype,
即Object构造函数的prototype属性指向的那个对象。

当然,Object.prototype对象也有自己的原型对象,那就是没有任何属性和方法的null对象,而null对象没有自己的原型。即Object.prototype = null

  • 读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
  • 如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。
  • 一级级向上在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。

constructor

prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。

由于constructor属性是定义在原型(prototype)对象上面,意味着可以被所有实例对象继承。

function A(){};
var a=new A();
console.log(a.constructor); //A()
console.log(a.constructor===A.prototype.constructor);//true
//之所以可以a.constructor是因为A的原型对象有这个属性;
//而a会继承原型对象的属性和方法,
//所以,a才可以调用constructor属性。

constructor属性的作用

  • 分辨原型对象到底属于哪个构造函数
function A(){};
var a=new A();
console.log(a.constructor===A) //true
console.log(a.constructor===Array) //false

instanceof运算符

instanceof运算符返回一个布尔值,表示指定对象是否为某个构造函数的实例。

因为instanceof对整个原型链上的对象都有效,所以同一个实例对象,可能会对多个构造函数都返回true。

注意,instanceof对象只能用于复杂数据类型(数组,对象等),不能用于简单数据类型(布尔值,数字,字符串等)。此外,null和undefined都不是对象,所以instanceof 总是返回false。

_ proto _

JS的万物都有__proto__属性。用于指向创建它的构造函数的原型对象。

为什么不用prototype指向原型?
因为prototype属性只有函数对象才拥有。

image.png
//创建一个构造函数
function People (name) {
  this.name = name;
}
//实例化一个构造函数
let g1 = new People('蜡笔小新')

那么,则会有:

People.prototype === g1.__proto__
《JavaScript 高级程序设计》的图 6-1

[[Prototype]] 其实就是__proto__。ECMA-262第5版中管这个指针叫[[Prototype]]。虽然在脚本中没有标准的方式访问[[Prototype]],但Firefox,Safari和Chrome在每个对象上都支持一个属性__proto__;而在其他实现中,这个属性对脚本是完全不可见的。

Object和Function

Object对象体系下:
一切对象的原型链最终都是.... → Object.prototype → null。例如定义一个num变量var num = 1,则num的原型链为x → Number.prototype → Object.prototype → null; 定义一个函数对象fnfunction fn() {},则fn的原型链为fn → Function.prototype → Object.prototype → null;等等...

原型链

Function体系下:
不考虑null的情况下(其中Object.prototype.__proto__ === null),Object.prototype为原型链的顶端,Function.prototype继承Object.prototype而产生,最后,FunctionObject和其它构造函数继承Function.prototype而产生。

原型链
注意:Function.prototype === Function.__proto__true

JS万物诞生记

https://img.haomeiwen.com/i17237086/1333d91c5d466cea.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240

总结

  • 同一个对象实例之间无法共享属性。即实例1和实例2的属性不能共享。
  • 构造函数的prototype属性叫做原型对象。(只有函数对象才有 prototype 属性)
  • 原型对象上的所有属性和方法,都会被对象实例所共享。
  • 原型链:读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
  • 如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”(overiding)。
  • 一级级向上在原型链寻找某个属性,对性能是有影响的。所寻找的属性在越上层的原型对象,对性能的影响越大。如果寻找某个不存在的属性,将会遍历整个原型链。
  • prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。
  • 由于constructor属性是定义在原型(prototype)对象上面,意味着可以被所有实例对象继承。
  • instanceof对象只能用于判断复杂数据类型(数组,对象等),不能用于简单数据类型(布尔值,数字,字符串等)
  • JS的万物都有proto属性。用于指向创建它的构造函数的原型对象。

参考文章

[详解Javascript中prototype属性(推荐)]

最详尽的 JS 原型与原型链终极详解,没有「可能是」。(一)
最详尽的 JS 原型与原型链终极详解,没有「可能是」。(二)
最详尽的 JS 原型与原型链终极详解,没有「可能是」。(三)
彻底搞懂Object和Function的关系

由一段代码引发的关于Object和Function的鸡和蛋问题的思考

JavaScript 世界万物诞生记

相关文章

  • JavaScript 原型、原型链与原型继承

    原型,原型链与原型继承 用自己的方式理解原型,原型链和原型继承 javascript——原型与原型链 JavaSc...

  • 原型与原型链相关

    前言 最近在整理原生JS的相关知识,发现关于原型和原型链涉及的知识对理解JS有很大的帮助。遂分享一下。 构造函数 ...

  • 原型、原型链、继承

    原型与原型链 什么是原型、原型链 原型:每一个对象(除null外)都有另一个对象与之相关联,这个另一个对象便称之为...

  • 2019-01-28

    原型与原型链

  • 原型与原型链  相关笔记

    全局对象Window ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局对...

  • 廖雪峰JS小记

    (function(){})() 原型,原型链 浅谈Js原型的理解JS 原型与原型链终极详解 对象 对象:一种无序...

  • Javascript(三)之原型继承理解

    进阶路线 3 原型继承 3.1 优秀文章 最详尽的 JS 原型与原型链终极详解 一 最详尽的 JS 原型与原型链终...

  • JS的__proto__和prototype

    最近在回顾JS的原型和原型链的知识,熟悉JS的同学都知道JS的继承是靠原型链实现的,那跟原型链相关的属性__pro...

  • JavaScript 面向对象第一篇

    1.原型链 ---- (实例对象与原型之间的连接 叫做原型链) 2. hasOwnproperty ----(看是...

  • 原型与原型链以及继承

    今天复习下原型与原型链的知识,以及记录新学的继承知识点。 知识点纲要 原型与原型链 es5与es6继承 什么是原型...

网友评论

      本文标题:原型与原型链相关

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