关于继承、实现new等

本文探讨JavaScript中的__ proto __、constructor和prototype属性,解释typeof和instanceof的工作原理,并模拟实现new操作符。深入讲解各种继承方式,包括借用构造函数、原型链、组合继承及其优化、原型式和寄生式继承,以及寄生组合式继承,分析它们的优缺点和适用场景。
摘要由CSDN通过智能技术生成
__ proto __ 和constructor是对象独有的,prototype是函数独有的;但是在js里函数也是对象,所以函数也有 __ proto __ 和constructor属性。

constructor对于引用类型来说是可以修改的,但是对于基本类型是只读的。

typeof 和 instanceof 原理

typeof 用于判断一个变量的类型,但是在判断object类型时,不能说明该object属于哪一种object

instanceof 用于监测constructor.prototype是否存在于参数object的原型连上

模拟实现new

关于new的模拟,首先需要知道会发生哪些事:

  1. 一个新对象被创建
  2. 调用其构造函数,并将this绑定到新创建的对象。
  3. 由构造函数返回的对象就是new表达式的结果

我们了解过一些关于原型、原型链知识点后知道一个实例可以:

  1. 访问到其构造函数(比如Foo)的属性
  2. 访问到其原型(比如Foo.prototype)的属性
function my_new() {
	var obj = new Object() // 创建一个新对象
	 Con = [].shift.call(arguments) // 取出需要(外部传入的)的构造函数
	 obj.__proto__ = Con.prototype // 将obj的原型指向构造函数,这样obj就可以访问到构造函数的属性
	 var result = Con.apply(obj, arguments) // 使用apply,改变构造函数的this到新建的对象,这样obj就可以访问到构造函数的属性
	 return typeof result === 'object' ? result : obj // 确保返回的是个对象
}

关于继承:
借用构造函数继承:

原理:将父级的构造函数this指向了子级构造函数的实例上
局限: 父级的原型链并没有被子级改变

function Mydad() {
	this.fatherName = 'hi dad' 
	console.log('dad的this' , this)
}
function Mychild() {
	Mydad.call(this)
	console.log('child的this' , this)
}
Mydad.prototype.sayHi = function(){
	console.log('hi you~~~')
};
var child1 = new Mychild()

console.log(child1)

在这里插入图片描述

  • 缺点 : 方法都在构造函数中定义,每次创建实例都会创建一遍方法,同时通过
Mydad.prototype.sayHi = function(){
	console.log('hi you~~~')
};

这种方式,子级就没有办法继承

原型链继承

原理:通过prototype的让实例对象的原型指向父级
局限:

  1. 如果实例了两个对象,针对他们的引用类型的属性来说,更改了一个对象。另一个对象也会被改变(因为他们共用一个原型对象),如果不是引用类型的属性,就不会存在这个问题。
  2. 创建子级实例时,没法向父级传参
    在这里插入图片描述
    局限如下:
    在这里插入图片描述
    在这里插入图片描述
组合继承(第一版)

原型链继承和构造函数继承一起使用
缺陷:在实例子类的时候,父类构造函数执行了两次

在这里插入图片描述

优化组合继承(第二版)

原理:如果想要继承父类的原型对象,就直接给他父类的原型对象
缺陷:会造成子类实例对象直接指向父级原型

在这里插入图片描述

优化组合继承(第三版)

主要就是要把构造器指回自己,
在这里插入图片描述

Mychild.prototype = Object.create(Mydad.prototype) // 增加了一级__proto__相当于隔离了Mychild,Mydad
// 使用下面这种方式也可以
Child.prototype = new Parent(); // 但是如上说了,会执行两次
原型式继承

原理: ES5 Object.create 的模拟实现,将传入的对象作为创建对象的原型
缺陷: 包含引用类型的属性值会始终共享,跟原型链继承一样

function mychild(obj) {
	function Mydad(obj) {
		this.fatherName = 'hi dad' 
	}
	Mydad.prototype = obj
	return new Mydad()
}
var person = {
    name: 'hahaha',
    type: [999]
}
var child1 = mychild(person)
var child2 = mychild(person)
child1.type.push(333)
console.log(child1)
console.log(child2)

在这里插入图片描述

寄生式继承

原理:创建一个仅用于封装继承过程的函数,该函数在内部以某种形式来做增强对象,最后返回对象。类似于借用构造函数一样,每次创建对象都会创建一遍方法

function mychild(obj) {
    var clone = Object.create(obj); // 创建一个新对象
    clone.sayName = function () {
        console.log('hi');  // 以某种方式来增强这个对象
    }
    return clone; // 返回这个对象
}
var person = {
    name: 'hahaha',
    type: [999]
}
var child1 = mychild(person)
var child2 = mychild(person)
child1.type.push(333)
console.log(child1)
console.log(child2)

寄生式继承就是对原型继承的扩展,可以新增自己的方法和属性
在这里插入图片描述

寄生组合式继承(害,就是上面组合继承的最优化的那一种)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值