原型对象?原型链?如何实现继承?

为什么要用原型对象

我们学习了构造函数的方式创建对象,你会发现,每一个对象的属性不一样这是一定的,但是它的方法似乎好像是一样的,如果我创建1000个对象,那岂不是内存中就有1000个相同的方法,那要是有10000个,那对内存的浪费可不是一点半点的,我们有没有什么好的办法解决,没错,我们可以把函数抽取出来,作为全局函数, 以了,上代码:

// 使用构造函数来创建对象
function Person(name, age) {
    // 设置对象的属性
    this.name = name;
    this.age = age;
    // 设置对象的方法
    this.sayName = sayName
}

// 抽取方法为全局函数
function sayName() {
    console.log(this.name);
}

但是,在全局作用域中定义函数却不是一个好的办法,为什么呢?因为,如果要是涉及到多人协作开发一个项目,别人也有可能叫sayName这个方法,这样在工程合并的时候就会导致一系列的问题,污染全局作用域,那该怎么办呢?有没有一种方法,我只在Person这个类的全局对象中添加一个函数,然后在类中引用?

// 使用构造函数来创建对象
function Person(name, age) {
    // 设置对象的属性
    this.name = name;
    this.age = age;
}

// 在Person类的原型对象中添加方法
Person.prototype.sayName = function() {
    console.log(this.name);
};

原型对象概念

  1. 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象,即显式原型,原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中。
  2. 以后我们创建构造函数时,可以将这些对象共有的属性和方法,统一添加到构造函数的原型对象中,这样不用分别为每一个对象添加,也不会影响到全局作用域,就可以使每个对象都具有这些属性和方法了。
  3. 如果函数作为普通函数调用prototype没有任何作用,当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__(隐式原型)来访问该属性。当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。

原型对象详解

Javascript 规定,每一个构造函数都有一个 prototype 属性,指向另一个对象(原型对象prototype)。
这个原型对象的所有属性和方法,都会被构造函数的实例访问(继承)。
这也就意味着,我们可以把所有对象实例需要共享的属性和方法直接定义在 prototype 对象上。

image-20220717233012985

原型链

img

概念:

  1. prototype是构造函数都有的属性,称为显示原型
  2. ___proto__是每个对象都有的属性,又称为隐式原型。
  3. 但是,___proto__不是一个规范属性,只是部分浏览器实现了此属性,对应的标准属性是[[Prototype]]。

什么是原型链

  1. 当访问一个对象的某个属性或方法时,会先在这个对象本身上查找,
  2. 如果没有找到,则会去它的_ proto _([[prototype]])隐式原型上查找,即它的构造函数的prototype
  3. 如果还没有找到就会再在构造函数的prototype的__proto__中查找,这样一层一层向上查找就会形成一个链式结构,我们称为原型链。

使用prototype实现继承

  1. 继承了父级原型上的方法
  2. 实例化多个Student都必须公用name和age
  3. 需要将构造器的指向更改回正确的指向

image-20220812184432601

// 定义一个构造函数
function Person(name,age){
    this.name = name,
        this.age = age,
        this.say = function(){
        console.log('我的名字叫'+name);
    }
}
// 给person的原型对象添加一个方法
Person.prototype.eat = function(){
    console.log('我是person原型添加的');
}

function Student(sex,state){
    this.sex = sex
    this.state = state
}

// 继承
Student.prototype = new Person('zjf',12)
Student.prototype.constructor = Student

// 实例化一个stu
let stu = new Student('男','在')
console.log(stu);
console.log('stu.sex:',stu.sex);
console.log('stu.name:',stu.name);
stu.say()
stu.eat()

使用call方法继承

  1. 实现了继承属性、但值都不相同
  2. 无法继承父类原型对象上的方法
function Person(name,age){
    this.name = name
    this.age = age
    this.say=function(){
        console.log('这是构造函数里面的');
    }
}
Person.prototype.like =function(){
    console.log('这个是原型对象上的方法');
}
// 让student构造函数里面的this变成
function Student(name,age,score){
    // Person.apply(this,arguments)
    // Person.call(this,arguments[0],arguments[1],arguments[2])
    Person.call(this,name,age,score)
}

let p  = new Person('zrs',19)
let stu = new Student('zjf',18,99)
console.log(p); //有link方法
console.log(stu); //没有link方法

image-20220813101303910

使用混合继承

  1. 混合了两种方法的优点
function Person(name,age){
    this.name = name
    this.age = age
    this.say=function(){
        console.log('这是构造函数里面的');
    }
}
Person.prototype.like =function(){
    console.log('这个是原型对象上的方法');
}
// 让student构造函数里面的this变成
function Student(name,age,score){
    this.score = score
    Person.call(this,name,age,score)
}


// 改变原型指向
//student.prototype本来是指向的它的原型对象
//现在student.prototype指向person构造函数创建的实例对象
Student.prototype = new Person() //不传值

let stu = new Student('zjf',18,99)
stu.say() //这是构造函数里面的
stu.like() //这个是原型对象上的方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端达闻西

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值