JavaScript - 构造函数,原型-原型链、相关解析

文章详细介绍了JavaScript中的构造函数及其工作原理,包括如何创建构造函数、实例化对象以及构造函数的原型链。接着讨论了构造函数的继承方式,如通过`call`方法的继承只能获取内部属性,而通过原型链继承可以共享方法但存在属性共享的问题。最后提到了组合继承,它结合了两种方式,但也带来了额外的父类实例属性。
摘要由CSDN通过智能技术生成

一、构造函数 

创建构造函数

// 创建一个构造函数
function Animal (name, age) {
    // 内部属性
	this.name = name
	this.age = age
    // 内部的方法
	this.action = () => {
	    console.log('叫')
	}
}

实例化对象

/*
    使用new关键字后,发生的隐式操作
		1. 创建一个实例对象 Dog
		2. 将Dog的__proto__属性赋值成 Animal.prototype属性 (相当于继承原型链上的属性以及方法)
		3. 执行Animal.call(Dog, '旺财', 12)
	如果不使用new关键字,Dog就为Animal返回的东西,没有为undefined
*/
const Dog = new Animal('旺财', 12)

验证刚才的观点

console.log(Dog) // Animal {name: '旺财', age: 12, action: ƒ}就是 Animal的实例
console.log(Dog.__proto__) // __proto__指向对应构造函数的"原型对象"
console.log(Animal.prototype) // 构造函数的原型对象
console.log(Dog.__proto__ === Animal.prototype) // true
console.log(Animal.prototype.isPrototypeOf(Dog)) // true 存在在Animal的原型链上

此为Animal.prototype打印出的结果,也就是原型对象,原型对象也有自己的__proto__指针,指向的是对应的原型对象,以此类推一直到顶层的null,即为原型链 ,此时的原型链上除了内置的方法外,没有其他的自定义的一些属性和方法,因为Animal中定义的属性以及方法都是私有的,对应每个创建好的实例对象

添加公共属性

// 直接像原型链上创建一个属性方法
Animal.prototype.perform = () => {
    console.log('我会表演', this)
}

那此时原型对象上的公共属性就会多一个perform,每一个实例化对象都是可以使用的 

 

一、构造函数的继承 

		// 还是动物的构造函数
		function Animal (name, age) {
			console.log(name, age)
			console.log(this)
			this.name = name
			this.age = age
			this.action = () => {
				console.log(`我是动物, 我叫${name},年纪${age}`)
			}
		}
		// 在原型上添加方法
		Animal.prototype.perform = () => {
			console.log('我会表演', this)
		}
		// 创建另一个构造函数,使用call将当前this传进去
		function Cat (name, age) {
			Animal.call(this, name, age)
			this.name = name
			this.age = age
		}
        // 创建cat1
        const cat1 = new Cat('小猫', 16)

 上面我们说过,new时隐式操作了三个步骤,创建,赋值原型,call改变this,那么这里我们用到了第一步以及第三步,看一下是什么效果

		console.log(cat1.action) // 存在
		console.log(cat1.__proto__ === Cat.prototype) // true
		console.log(Cat.prototype.__proto__ === Animal.prototype) // false
		console.log(cat1.perform) // undefined

        // 第一句: 可以看出,此类继承,继承了公共Animal的action内部的方法,
        // 第二句: cat1的__proto__指向的一定是Cat的prototype属性,因为是使用new创建的cat1
        // 第三句: 证明Cat这个构造函数并没有继承实际Animal原型对象
        // 第四句: 证明cat1并没有在Animal以下的这条原型链上,因为无法读取原型链上的方法,也就证明,Cat使用call这种继承方法,只能继承对应内部的属性,无法继承原型链上的属性

二、原型链继承

		// 还是动物的构造函数
		function Animal (name, age) {
			console.log(name, age)
			console.log(this)
			this.name = name
			this.age = age
			this.action = () => {
				console.log(`我是动物, 我叫${name},年纪${age}`)
			}
		}
		// 在原型上添加方法
		Animal.prototype.perform = () => {
			console.log('我会表演', this)
		}
		// 创建另一个构造函数
		function Cat (name, age) {
			this.name = name
			this.age = age
		}
		
		Cat.prototype = new Animal(); // 此时Cat.prototype.constructor==Animal
		Cat.prototype.constructor = Cat; // 修正constructor指向
        
        const cat1 = new Cat('小猫', 16)
console.log(cat1.action) // 存在
console.log(cat1.__proto__ === Cat.prototype) // true
console.log(Cat.prototype.__proto__ === Animal.prototype) // true
console.log(cat1.perform) // 存在

// 第一句: action存在说明,继承了Animal身上的属性,(但此处属性是共享的互相影响的)
// 第二句: 一样使用new 创建的 cat1的__proto__一定是Cat的prototype
// 第三句: 说明原型继承了,所以第四句也是可以访问到,原型链上的方法的
// 第四句: 可以访问,因为存在同一个原型链上

// 缺点: 属性共享,改一处,其他地方也跟着改变
// 缺点: 无法传参数到Animal中

三、组合继承

		// 还是动物的构造函数
		function Animal (name, age) {
			console.log(name, age)
			console.log(this)
			this.name = name
			this.age = age
			this.action = () => {
				console.log(`我是动物, 我叫${name},年纪${age}`)
			}
		}
		// 在原型上添加方法
		Animal.prototype.perform = () => {
			console.log('我会表演', this)
		}
		// 创建另一个构造函数
		function Cat (name, age) {
			this.name = name
			this.age = age
			// 加了这么一句
			Animal.call(this, name, age)
		}
		
		Cat.prototype = new Animal(); // 此时Cat.prototype.constructor==Animal
		Cat.prototype.constructor = Cat; // 修正constructor指向
        const cat1 = new Cat('小猫', 16)

        // 缺点: 由于调⽤了2次⽗类的构造⽅法,会存在⼀份多余的⽗类实例属性

总结: 构造函数实例化出来的对象,有一个__proto__的隐藏属性,它相当于一个指针,指向的就是对应构造函数的原型对象,而构造函数上也存在一个prototype的属性,指向的也是这个原型对象,那这个原型对象也拥有__proto__以此类推

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值