JS高级-原型与原型链

285 阅读6分钟

函数高级

原型与原型链

原型

1.函数的prototype属性

  • 每个函数都有一个prototype属性,它默认指向一个Object空对象\textcolor{LightCoral}{Object空对象}(即:原型对象),可在该对象中添加方法

  • 指向的空对象(原型对象)中有一个属性constructor,指向函数对象\textcolor{LIghtCoral}{函数对象}

  • console.log(Date.prototype.constructor===Date)
    

2.给原型对象添加属性(一般是方法)===>实例对象(构造函数)可以访问

  • 作用:构造函数的所有实例对象自动拥有其原型对象中的属性(方法)

显式原型与隐式原型

1.每个函数都有一个prototype属性,即显式原型\textcolor{LightCoral}{显式原型}(属性),默认指向Object空实例对象

//1.定义构造函数
function Fn() {//内部语句:this.prototyoe = {} 在声明后默认指向空对象
    //Fn相当于全局变量,存储其函数对象的地址值
}
console.log(Fn.prototype)//保存的地址值

2.每个实例对象都有一个__proto__,可称为隐式原型\textcolor{LightCoral}{隐式原型}(属性),指向其构造函数原型对象

//2.创建实例对象
var fn = new Fn() //内部语句:this.__proto__ = Fn.prototype
console.log(Fn.prototype===fn.__proto__)//true  __proto__保存地址值
//3.给原型添加方法
Fn.prototype.test = function () {
    console.log("test()")
}
//4.实例对象调用原型对象中定义的函数(方法) 
//规则:先在本身属性上查找,没有再通过属性__proto__查找其对应原型对象内是否有该方法
fn.test()

3.实例对象的隐式原型的值为其对应构造函数的显式原型的值

4.内存结构图

image.png 5.总结

  • 构造函数prototype属性:在定义函数\textcolor{LightCoral}{定义函数}时自动添加,默认指向一个的Object实例对象(没有我们所指定的的属性或方法),除了Object,console.log(Object.prototype instanceof Object) //false 没有__proto__属性,console.log(Function.prototype instanceof Object) //true
  • 实例对象的__proto__属性:创建对象\textcolor{LightCoral}{创建对象}时自动添加,默认值为构造函数的prototype属性值(地址值)

原型链(隐式原型链)

作用:查找对象的属性(方法)

步骤:

  • 访问一个对象的属性时

  • 先在自身属性中寻找,找到就返回

  • 若没有,则沿着隐式原型属性_proto__这条链向上(直到原型链尽头_

    Object.prototype.__proto__ == null
    

    )查找,找到返回

  • 如果最终也没找到,则返回undefined

【注】\textcolor{LightCoral}{【注】}JS引擎会先加载内置的函数,比如Object,因而在查找属性是并不是找到构造函数的原型对象就结束了,还需要往上查找,某构造函数的原型对象是一个空的Object对象的是说其中没有我们指定的属性或方法,但它其实也是Object构造函数\textcolor{LightCoral}{Object构造函数}实例对象,含有**_proto_属性指向Object构造函数\textcolor{LightCoral}{Object构造函数}原型对象**。

【注】\textcolor{LightCoral}{【注】}任何函数(Object()也是)都有一个显式原型属性和一个隐式原型属性(为Function构造函数的实例对象包括它本身\textcolor{LightCoral}{包括它本身})且!所有函数的隐式原型属性都应该相等!因为都是var fn = new Function()产生。Funciton = new Function(),Function既是构造函数又是实例对象,表明显式原型属性等于隐式原型属性

image.png

Function._proto_===Function.prototype,普通函数的显式原型指向一个空的Object实例对象,其隐式原型指向Function.prototype!

image.png

原型链属性问题

  1. 读取\textcolor{LightCoral}{读取}对象的属性值时:会自动到原型链中查找
  2. 设置\textcolor{LightCoral}{设置}对象的属性值时:不会查找原型链,如果当前对象没有此属性,会直接添加此属性并赋值
  3. 方法\textcolor{LightCoral}{方法}一般定义在原型中(这样通过该构造函数new的实例对象都能用,不需要每个对象都设置),属性\textcolor{LightCoral}{属性}一般通过构造函数定义在对象本身上(属性多样性\textcolor{LightCoral}{属性多样性},构造函数可以构造不同的实例对象,但其隐式原型均指向构造函数的显式原型)

探索instanceof

1.instanceof是如何判断的?

  • 表达式:A instanceof B

  • 如果B函数的显式原型对象在A实例对象的原型链(隐式原型链)上有交集,返true,否则返false

  • 只要B是Object,A只要不是Objcet,都为true

    function fn() {}
    var f1 = new fn()
    console.log(f1 instanceof fn) //true
    console.log(f1 instanceof Object) //true  原型链尽头 Object.prototype  f1是fn函数的实例对象指向fn.prototype,同时fn.prototype是Object函数的实例对象其隐式原型指向Object.prototype
    
    
    console.log(Object instanceof Function) //true 任何函数都是Function的实例对象
    console.log(Object instanceof Objcet) /* true 
    Object是构造函数 B为构造函数 Object.prototype(原型链尽头),A为Function的实例对象,因而其隐式原型指向Funciton.prototype,又因为Funciton.prototype为Object的实例对象,故指向Object.prototype*/
    console.log(Function instanceof Function) //true Function = new Funciton()
    console.log(Funciton instanceof Object) //true
    
    function fo() {}
    console.log(Object instanceof fo) //fasle 
    //Object走原型链到Object.prototype,任何函数都是Funcion的实例对象,因而其__proto__先指向Funciton.prototype,该显式原型又是Object的实例对象因而其__proto__指向Object.prototype,这是原型链走势,对于fo只走一步即fo.prototype,虽然其最后仍然指向Object.prototype,但因为其作为B,Object作为A,所以没有交集,反false
    

2.Function是通过new自己产生的实例

原型面试题

var A = function A () {
}//定义构造函数A
A.prototype.n = 1 //A的显式原型中添加n属性
var b = new A() //b为A的实例对象1 确定其隐式原型指向为最初的

A.prototype = {
    n: 2,
    m: 3
}//A的显式原型赋值新的对象地址值,之前的原型指向被更改
var c = new A()//c为A的实例对象2 此处隐式原型指向已经更改为新的
console.log(b.n,b.m,c.n,c.m)//1 undefined 2 3
function F1() {}//声明构造函数
Object.prototype.a = function(){
    console.log("a()")
}//原型链尽头设置方法a
Function.prototype.b = function(){
    console.log("b()")
}//Function显式原型设置方法b 其内部有隐式原型指向原型链尽头Object.prototype 任何函数的隐式原型能指向该显式原型,注意是函数不是其构造的实例对象!
var f = new F()//f为构造函数F的实例对象  注意不是Funciton!
f.a()//本身没有在原型链上找,找到原型链尽头 "a()"
f.b()//报错没有b这个函数   其指向应该是Object.prototype,但b方法在Function.prototype上并不在F函数上,F1函数的隐式原型才指向Function,才有b方法
F1.a()//"a()"  通过隐式原型链找到Object.prototype的方法a
F1.b()//"b()"

image.png

【注】构建函数new的实例对象,通过原型链最终肯定会指向原型链Object.prototype,顺序是先实例对象的隐式原型指向构建函数的显式原型,然后构造函数的显式原型指向原型链尽头,这期间实例对象的隐式原型并没有指向Function.prototype,只有\textcolor{LightCoral}{只有}构建函数的隐式原型\textcolor{LightCoral}{隐式原型}才指向Function.prototype,因而若Function.prototype有方法定义,只有\textcolor{LightCoral}{只有}构建函数才能调用因为在其隐式原型链上,但是实例对象无法调用,只能调用其构建函数的显式原型和原型链尽头上的方法!