原型对象和原型继承

1. 原型对象

  • 构造函数的原型属性 prototype, 指向其原型对象;原型对象的 constructor 属性 指向该原型对象对应的构造函数。

  • 作用:共享属性和方法;当实例对象找不到成员时,便会找原型对象上的成员。

  • 场景:构造函数中创建属性,在原型对象中创建方法,使得代码更加灵活。

<script>       
    function Person(uname, age, sex) {
        this.uname = 'yb'
        this.age = 23
        this.sex = '男'
        this.sing = function () {
            console.log('构造函数sing')
        }
    }

    Person.prototype.sex = '女'
    Person.prototype.sing = function () {
        console.log('原型sing')
    }
    Person.prototype.dancing = function () {
        console.log('原型dancing')
    }
    let obj = new Person()
    console.log(obj)

    // 当构造函数和其原型对象的方法、属性同名时,以构造函数为准
    // 访问实例对象方法和属性,会先去它的构造函数中找,当构造函数中没有时,再去构造函数的原型对象中找
    console.log(obj.sex)
    obj.sing()
    obj.dancing()
</script>

在这里插入图片描述


2. 封装和继承

2.1 封装

  • 构造函数体现了面向对象的封装特性。
  • 构造函数实例创建的对象彼此独立、互不影响。

2.2 继承

2.2.1 原型继承

把父类的实例对象赋值给子类的原型对象,再指回子类构造函数本身。

操作:独立创建公共对象,里面包含公共属性和方法,然后实例化赋值给构造函数的原型对象。这样可以使得公共属性和方法共享。

<script>
    // 1.字面量创建对象,存放公共属性和方法
    let obj = {
        college: '黑魔法学院',
        faculty: '计算机学院',
        year: 2022,
        major: function () {
            console.log('计算机科学与技术')
        }
    }

    // 2.创建独立构造函数
    function Stu1() {
        this.uname = '小摩托'
        this.age = 21
        this.id = 2022762018
        this.hobby = function () {
            console.log('赛车、滑板')
        }
    }  
    
    // 3.继承公共对象中的属性和方法
    // 3.1 将公共对象赋值给独立构造函数的原型对象(赋值既覆盖)
    Stu1.prototype = obj
    // 3.2 再将原型对象指回构造函数
    Stu1.prototype.constructor = Stu1
    console.log(Stu1.prototype)

    // 4.实例化独立对象
    let n1 = new Stu1()
    console.log(n1)
    console.log(n1.college)
    </script>

结果如下图所示:
表示继承成功


  • 这种用字面量创建公共对象的继承会出现问题,如下:
<script>
    // 1.字面量创建对象,存放公共属性和方法
    let obj = {
        college: '黑魔法学院',
        faculty: '计算机学院',
        year: 2022,
        major: function () {
            console.log('计算机科学与技术')
        }
    }

    // 2.创建独立构造函数
    function Stu1() {
        this.uname = '小摩托'
        this.age = 21
        this.id = 2022762018
        this.hobby = function () {
            console.log('赛车、滑板')
        }
    }

    function Stu2() {
        this.uname = '小飞侠'
        this.age = 22
        this.id = 2022782023
        this.hobby = function () {
            console.log('画画、花草')
        }
    }

    // 3.继承公共对象中的属性和方法
    Stu1.prototype = obj
    Stu1.prototype.constructor = Stu1

    // 4.实例化独立对象
    let n1 = new Stu1()
    console.log(n1)
    // console.log(n1.college)

    //  Stu2继承
    Stu2.prototype = obj
    Stu2.prototype.constructor = Stu2
    console.log(Stu2.prototype)

    // 实例化第二个对象
    let n2 = new Stu2
    console.log(n2)
    </script>

如图:Stu1 的原型对象的constructor指向发生了变化,不再是其原来对应的构造函数:

在这里插入图片描述
问题分析:
Stu1 和Stu2 的原型对象用的是同一份数据,传递的是同一份地址,当Stu2 的原型对象指向被修改,Stu1的指向也会被修改。


  • 最终原型继承:使用构造函数创建对象
<script>
    // 1. 创建公共构造函数
    function Students() {
        this.college = '黑魔法学院'
        this.faculty = '计算机学院'
        this.year = 2022
        major = function () {
            console.log('计算机科学与技术')
        }
    }

    // 2. 创建独立构造函数
    function Stu1() {
        this.uname = '小摩托'
        this.age = 21
        this.id = 2022762018
        this.hobby = function () {
            console.log('赛车、滑板')
        }
    }

    function Stu2() {
        this.uname = '小飞侠'
        this.age = 22
        this.id = 2022782023
        this.hobby = function () {
            console.log('画画、花草')
        }
    }

    // 3. 继承 
    // 3.1 实例化公共对象 并将 实例化对象 赋值给 独立构造函数的原型对象
    Stu1.prototype = new Students()
    // 3.2 再将原型对象指回构造函数
    Stu1.prototype.constructor = Stu1

    // Stu2 继承 
    Stu2.prototype = new Students()
    Stu2.prototype.constructor = Stu2

    // 实例化独立对象
    let n1 = new Stu1()
    console.log(n1)
    let n2 = new Stu2
    console.log(n2)
</script>

每一次实例化公共对象,都相当于重新创建一份对象 ,使得两个构造函数的原型对象不再使用同一份地址,其指向也就互不影响。

在这里插入图片描述


  • 方法中的this指向的是当前实例化对象,而不是方法 所在的原型对象。(谁调用,指向谁)
<script>
    function fn() {
        this.a = 1
        this.b = 3
        this.sum = function () {
            return this.a + this.b
        }
    }

    function fn2() {
        this.a = 3
        this.b = 4
    }

    // fn2 继承了fn的函数  函数被调用时,this 指向的是当前继承的对象,而不是继承的函数所在的原型对象。
    fn2.prototype = new fn()
    fn2.prototype.constructor = fn2

    let n = new fn2()
    console.log(n.sum())  // 结果为 7 而不是 4     
</script>

2.2.2 原型链

  • 每个实例对象都有一个属性 _ proto _,指向构造函数的原型对象。原型对象也有自己的原型对象,层层指向直到一个对象的原型对象为 null为止。

  • 原型链:由原型构成的链状结构,提供了成员查找机制。
    在这里插入图片描述
    当前实例对象能够调用和访问原型链上的所有属性和方法,当有相同属性和方法时,采用就近原则。

  • 在对象原型上添加方法

<script>
    // 1. 
	let obj = new Object({ a: 'wel', b: 'come' })
	Object.prototype.join = function () {
    	return this.a + this.b
	}
	console.log(obj.join())
	// 2.
	let arr = new Array(1, 2, 3, 5, 7, 8)
	Array.prototype.sum = function () {
  		let add = 0
    	for (let i = 0; i < this.length; i++) {
        	add += this[i]
    	}
    	return add
	}
	console.log(arr.sum())  
</script>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值