原型和原型链解析

原型

要理解原型首先需要明确几个概念:
1、__proto__
每个引用数据类型(如Object、Array、function)的对象实例,都有这个是属性,同时这个属性也是一个对象;

2、prototype
只有函数对象实例,有这个属性,且这个属性也是个对象;每个prototype都有一个constructor指向这个方法;

3、__proto__和 prototype关系
每个对象实例的__proto__都指向其构造函数的 prototype

看下面的代码:

	let myObj= {
      name:"张三"
    }
    console.log(myObj.__proto__ === Object.prototype)  // true
    console.log(myObj.prototype)  // undefined

    const comd = function comd(){}
    console.log(comd.prototype.constructor)   // ƒ comd(){}

prototype 就是原型,存放属性和方法的最初对象。

原型链

首先看一个普通对象的原型调用关系:

	let myObj= {
      name:"张三"
    }

    myObj.showName()  // myObj.showName is not a function

    Object.prototype.showName = function(){
      console.log("我是"+this.name)
    }

    myObj.showName() // 我是张三

在创建myObj 时并没有声明 showName 方法,所以调用时会提示找不到方法的错误;

当我们给Object原型中声明了showName方法,再次使用myObj调用时就可以打印正确的信息。

既然通过上面第(3)个概念知道:myObj.__proto__ === Object.prototype,所以可以猜测myObj调用showName 时,是通过__proto__调用了 Object.prototype的showName 方法。

既然提到了构造函数,那么我们看看通过构造函数创建的对象实例调用的顺序:

	function People(){
      this.name = "张三"
    }

    People.prototype.showName = function(){
      console.log("我是"+this.name)
    }

    let myPeople = new People()

    console.log(myPeople.__proto__ === People.prototype) // true
    
    myPeople.showName() // 我是张三

    myPeople.showName = function(){
      console.log("我不是"+this.name)
    }

    myPeople.showName() // 我不是张三

可以看到,myPeople 实例在没有声明showName 方法的时候,会调用构造函数People原型中的方法;

当我们给myPeople 声明了showName 方法后,在调用时打印的内容就是新声明的showName 中的内容。

结论:当调用对象实例的方法时,会首先查找自身有无该方法并执行,如果没有会查找其构造函数的原型方法并执行。

根据上面的结论,我们又有疑问了:这种查找什么时候结束?那么看下面这段代码:

	function People(){
      this.name = "张三"
    }

    let myPeople = new People()

    console.log(myPeople.__proto__ === People.prototype) // true

    myPeople.showName() // myPeople.showName is not a function

    console.log(People.prototype.__proto__ === Object.prototype) // true 因为prototype本质是个对象

    Object.prototype.showName = function(){
      console.log("我是"+this.name)
    }

    myPeople.showName() // 我是张三

这里我们没有给 myPeople 和 People.prototype 声明showName 方法,所以调用会报错找不到方法。

但是当我们给Object的原型中声明 showName 方法,在通过myPeople 调用,就可以正常打印内容。

原因很简单:当myPeople调用方法时,首先查找自身没有这个方法,所以会通过myPeople.__proto__从构造函数的原型中(People.prototype)查找该方法,但是也没有找到。
由于prototype 本身是个对象,所以会通过People.prototype.__proto__从prototype 的构造函数中(即Object)的原型中查找,在Object.prototype找到了我们声明的showName,所以执行了该方法。

那么对象属性是否和方法表现一致呢?

	function People(){
      this.name = "张三"
    }

    let myPeople = new People()

    Object.prototype.age = 30

    console.log(myPeople.age) // 30

通过上面代码可以看到,属性也是可以通过上述递归查找的方式找到的。那么可以得出结论:

原型链就是通过__proto__递归查找prototype原型的过程。

在ES6中引入了class的概念,也是创建对象及实例的方法之一,那么它支持原型吗?看下面的代码:

	class People {
      constructor(name){
        this.name = name;
      }
    }
    let myPeople = new People("张三")

    People.prototype.age = 30

    console.log(myPeople.age) // 30

    Object.prototype.sex = "男"

    console.log(myPeople.sex) // 男

可以看到上面章节所使用的原型设置方法,还是可以生效的,所以可以肯定:

通过class是构造函数的另外一种写法,同样带有prototype。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值