实例、原型、构造函数的关系,以及继承

实例、原型、构造函数的关系:

function Parent () {
  this.name = 'name'
}
var person = new Parent()

1.概念:

构造函数: js中所有的函数都可以作为构造函数,前提是被new操作符操作。通常函数名首字母大写
实例: 接收了被new实例化后新建的对象
原型:构造函数都有一个prototype属性,这个属性指向原型对象。

在上述代码中 构造函数是Person,实例是person 。

2.关系:

new操作符作用于构造函数,得到实例。实例对象有一个_proto_(每个对象都有_proto_)属性指向该实例的构造函数对应的原型对象。
构造函数的prototype(所有函数都有的属性)指向原型对象。原型对象例也有一个constructor属性,指向构造函数。
在这里插入图片描述

函数的原型对象组成:

function fn(){}
console.log(fn.prototype) //输出如下图

在这里插入图片描述

3.确定原型和实例的关系:

1.instanceof : 只要实例和原型链中出现过的构造函数都会返回true


person instanceof  Person      // true

2.isPrototype():只要是原型链中出现过的原型,都可以说是该原型链所派生的原型实例,会返回true。

Person.prototype.isPrototype(person)

补充:检查对象自己定义的属性,需使用所有对象从 Object.prototype 继承的 hasOwnProperty 方法,它不会遍历原型链的方法. 用法p.hasOwnProperty(‘name’) // 返回布尔值

补充:js 写new操作符的工作原理:

var newObj = function(func){
    var o= {}    // 1.新建一个对象
    o.prototype = func.prototype  //指定原型
    var k =func.call(o);  // 执行构造函数,this指向该实例
    if(typeof k === 'object'){  //构造函数返回了对象,最后返回该对象
        return k;
    }else{
        return o;
    }
}
var parent1 = newObj(Parent)


4.原型链

当我们从一个对象里找某个属性,如果在当前对象没找到,那么会从通过_proto_属性一直往上找,如果找到了Object对象上还没找到的话,则这个属性才是真的不存在,否则只要找到了,这个属性都是存在的。像这样让原型对象等于另一个类型的实例,通过_proto_将对象和原型联系起来组成的链条关系叫做原型链。

原型链关系图(图源网络)

继承:

继承与原型链

1.构造函数实现继承

核心代码
function P(){}
function C(){P.call(this)}

优点:子类构建实例可以向父类传参
缺点: 子类实例的方法每次需要单独创建

function Parent(){
 this.name='zhangsan'
}
function Child(){
 Parent.call(this)
}
Parent.prototype.age = 29
var c1 = new Child()
console.log(c1.name)   //zhangsan
console.log(c1.age)  // undefined
缺点:实例对象c1访问不到父级原型上的(age)属性

2.原型链实现继承:

function P(){}
function C(){}
C.prototype =new P()
核心: 将父类实例作为子类实例的原型
优点:能继承到原型上的所有属性
缺点: 即原型链继承引用类型属性时,在任意实例对象上改变该属性,所有实例对象属性都会变化。(父子类构建实例不能向父类传参

function Parent(){
    this.name = 'parent'
    this.play = [1,2,3]
}
function Child(){
    this.type = 'child';
}
Child.prototype = new Parent();    //把父类实例赋值给子类原型
var child1 = new Child();    
console.log(child1.play)    // [1,2,3]
child1.play[0]=0     // 改变实例对象child1里的数据,child2对应也会变。 
var child2 = new Child()
console.log(child2.play)     //[0,2,3]

3.组合继承简化

核心:结合原型链和构造继承,兼具了二者优点
缺点:调用了两次父类构造函数,会造成性能上的浪费

function Parent(){}
function Child(){
  Parent.call(this)   // 第二次调用
}
Child.prototype = new Parent()  // 第一次调用Parent

4.使用Object.create实现继承

function Parent(){
    this.name = 'parent1'
    this.play = [1,2,3]
}
    
function Child(){
    Parent.call(this);
    this.type = 'parent2';
}
//var obj={}
//obj.prototype=Parent.prototype
//Child.prototype = obj  这三句话等价于接下来的一句
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor=Child

console.log(Child.prototype.constructor)
console.log(Parent.prototype.constructor) 输出如下

在这里插入图片描述

注:Object.Create() 是es5引入的方法,可以调用该方法来创建一个新对象, 使用现有的对象来提供新创建的对象的__proto__。即新对象的原型就是()传入的第一个参数.

语法:Object.create(proto, {propertiesObject})
proto: 新创建对象的原型对象。
propertiesObject: 可选,添加新创建对象的自定义属性

var b = Object.create(a);
//原型链 b ---> a ---> Object.prototype ---> null
console.log(b.属性); // (继承而来)

5.ES6 的Class Extends实现继承 (待补充)

而ES6先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。
super关键字可以调用父类中的函数。
class A {}

class B extends A {
constructor() {
super();
}
}

// 定义父级
class Polygon {
  constructor(height, width) {
    this.name = 'Polygon';
    this.height = height;
    this.width = width;
  }
  sayName() {
    console.log('Hi, I am a ', this.name + '.');
  }
}


class Square extends Polygon {
  constructor(length) {
    super(length, length);
    this.name = 'Square';
  }

  get area() {
    return this.height * this.width;
  }

  set area(value) {
    this.area = value;
  }
}

let s = new Square(5);

s.sayName();
console.log('The area of this square is ' + s.area);

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值