原型 原型链

原型和原型链

原型

原型分为显式原型和隐式原型。

  1. 每个函数function对象都有prototype(显式原型),在定义函数的时候自动添加,默认值就是一个空对象。
  2. 每个对象都有__proto__,创建对象的时候自动添加的,值为构造函数的prototype指向的属性

当使用new 新建一个对象的时候:

  1. 创建一个新对象,这个新对象的__proto__属性指向构造函数的prototype属性(第二条 对象__proto__指向构造函数prototype的原因
  2. 构造函数执行环境的this指向这个新对象
  3. 执行构造函数中的代码,通过this给新对象添加新的成员属性或方法。
  4. 如果return 返回一个基本数据类型的变量就返回构造新的对象 如果写死了return返回的对象就返回写死的对象 不返回新对象

原型和原型链

原型

原型分为显式原型和隐式原型。

  1. 每个函数function对象都有prototype(显式原型),在定义函数的时候自动添加,默认值就是一个空对象。
  2. 每个对象都有__proto__,创建对象的时候自动添加的,值为构造函数的prototype指向的属性

原型链

请添加图片描述

如图所示:Person为构造函数,通过new调用实例化出对象p1。

  1. 函数Person的prototype指向原型对象,通过new调用之后p1__proto__指向原型对象,两者没有直接关联,通过原型对象联系在一起
  2. 同时Person对象作为一个对象,也有自己的隐式原型__proto__,所有的函数实例都可以理解为new Function构造得到,所以函数实例的__proto__指向Function
  3. Function.prototype=Function.__proto__ ,因为函数Function即是函数,又是对象。在作为对象时,是通过new Function()获得的。
  4. Object函数是一个函数对象,所以其__proto__也是指向Function
  5. Object是所有对象的基类,所以原型对象都是Object的实例
  6. 原型链的终点就是null

其实原型链主要分成两种情况

  • 函数的继承

    • 函数的继承链为prototype
  • 对象的继承

    • 对象的继承链为__proto__
对象的继承

当使用new 新建一个对象的时候:

  1. 创建一个新对象,这个新对象的__proto__属性指向构造函数的prototype属性(第二条 对象__proto__指向构造函数prototype的原因
  2. 构造函数执行环境的this指向这个新对象
  3. 执行构造函数中的代码,通过this给新对象添加新的成员属性或方法。
  4. 如果return 返回一个基本数据类型的变量就返回构造新的对象 如果写死了return返回的对象就返回写死的对象 不返回新对象

继承

继承就是实现代码的复用。(ts是鸭子类型,继承关系并不需要真的继承,看类型就ok

es5有三种继承方式:

  1. 原型链继承
  2. 借用构造函数实现继承
  3. 寄生组合式继承

es6继承方式:

  1. 类继承extends

使用原型链继承

直接修改函数的prototype

 function Person(){
     this.friend=[]
     this.name=111
 }
 ​
 function Student(){
     this.sno=111
 }
 ​
 let p=new Person()
 Student.prototype=p
 ​
 let stu1=new Student()
 let stu2=new Student()
 stu1.friend.push('ali')
 stu1.name='222'
 console.log(stu1.friend,stu1.name)
 console.log(stu2.friend,stu2.name)
 // [ 'ali' ] 222
 // [ 'ali' ] 111

弊端:

  1. 因为原型是同一个对象,所以修改原型上的引用类型会导致其他读取也有问题(不过这个是原型本身的问题)
  2. 不好传递参数

使用借用构造函数实现继承

将子类的prototype指向父类的实例

 function Person(name,age,friends){
     this.name=name
     this.age=age
     this.friends=friends
 }
 ​
 function Student(name,age,friends){
     //相当于在new指向的空对象里面一个一个赋值Person的属性
     Person.call(this,name,age,friends)
     this.sno=111
 }
 ​
 let p=new Person()
 Student.prototype=p
 ​
 let stu1=new Student('stun',18,['lucy'],111)
 console.log(stu1)
 //Person { name: 'stun', age: 18, friends: [ 'lucy' ], sno: 111 }

注意

  1. 注意13行,new p的时候是没有给Person传参的,所以p的nameagefriend都是undefined,就算第9行Person.call了,其实并没有给p赋值,this指向的是父类的空对象,不是p!

在这里插入图片描述
弊端:

  • 属性都在自己身上其实p就不用重复了
  • 调用了两次 亲代类的构造函数 其实没什么必要

寄生组合式继承

拷贝父类的显式原型,将拷贝的原型对象的constructor指向自己。

 function Person(name,age,friends){
     this.name=name
     this.age=age
     this.friends=friends
 }
 ​
 function Student(name,age,friends){
     //相当于在new指向的空对象里面一个一个赋值Person的属性
     Person.call(this,name,age,friends)
     this.sno=111
 }
 ​
 //子类继承父类
 let p=Object.create(Person.prototype)
 Student.prototype=p
 Student.prototype.constructor = Student;
 ​
 let stu1=new Student('stun',18,['lucy'],111)
 console.log(stu1)
 //Person { name: 'stun', age: 18, friends: [ 'lucy' ], sno: 111 }

补充:

  1. Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型

es6:

extends

引入类关键字class,但是其实就是function的语法糖。extends不止能继承类,也能继承普通的构造函数。

es6规定,子类一定要在构造函数construnctor()里面调用父类的构造函数super()!因为ES6 的继承机制,与 ES5 完全不同。ES5 的继承机制,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上面,即“实例在前,继承在后”。ES6 的继承机制,则是先将父类的属性和方法,加到一个空的对象上面,然后再将该对象作为子类的实例,即“继承在前,实例在后”。 这就是为什么 ES6 的继承必须先调用super()方法,因为这一步会生成一个继承父类的this对象,没有这一步就无法继承父类。

es5:在子类实例上添加父类实例的方法

es6:先生成父类实例,然后再添加子类的属性,实例变成子类

 class Point {
   constructor(x, y) {
     this.x = x;
     this.y = y;
   }
 }
 ​
 class ColorPoint extends Point {
   constructor(x, y, color) {
     this.color = color; // ReferenceError
     super(x, y);
     this.color = color; // 正确
   }
 }

上面代码中,子类的constructor()方法没有调用super()之前,就使用this关键字,结果报错,而放在super()之后就是正确的(不涉及this关键字的语句放在super之前也是ok的

a instance of b

->a.proto*n==b.prototype(a是不是b(类型)的实例

就是看b在不在a的原型链上instanceof运算符只能用于对象,不适用原始类型的值。

instanceof的原理是检查右边构造函数的prototype属性,是否在左边对象的原型链上。有一种特殊情况,就是左边对象的原型链上,只有null对象。这时,instanceof判断会失真。

var obj = Object.create(null);
typeof obj // "object"
obj instanceof Object // false

上面代码中,Object.create(null)返回一个新对象obj,它的原型是nullObject.create()的详细介绍见后文)。右边的构造函数Objectprototype属性,不在左边的原型链上,因此instanceof就认为obj不是Object的实例。这是唯一的instanceof运算符判断会失真的情况(一个对象的原型是null)。

注意:
typeof在node环境下是取的原型对象的constructor

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值