JS多种继承方式

数据类型判断。

typeof
可以正确识别:undefined、boolean、number、string、symbol、function等类型的数据,但是对于其他的都会认为是object,比如Null、Date等,所以通过typeof来判断数据类型会不准确。但是可以使Object.prototype.toString实现。

function typeOf(obj){
	return Object.prototype.toString.call(obj).slice(8,-1).toLowerCase()	
}
typeOf([]) //'array'
typeOf({}) // 'object'
typeOf(new Date) //'date'

继承

原型链继承

	function Animal(){
		this.colors = ['black','white']
	}
	Animal.prototype.getColor = function(){
		return this.colors
	}
	function Dog(){}
	//改变Dog的原型对象 为 Animal实例
	Dog.prototype = new Animal()
	
	let dog1  = new Dog()
	dog1.colors.push('brown')
	let dog2 = new Dog()
	console.log(dog.colors) // ['black','white','brown']

原型链继承存在的问题:

  • 问题1:原型中包含的引用类型属性将被所有实例共享;
  • 问题2:子类在实例化的时候不能给父类的构造函数传参;

借用构造函数继承

	function Animal(name){
		this.name = name
		this.getName = function(){
			return this.name
		}
	}
	function Dog(name){
		// 借用Animal函数
		Animal.call(this,name)
	}
	Dog.prototype = new Animal()

借用构造函数实现继承 解决了原型链继承的2个问题:引用类型共享问题以及传参问题。但是由于方法必须定义在构造函数中,所以会导致每次创建子类实例都会创建一遍方法。

组合式继承

组合式继承 结合了原型链和盗用构造函数,将两者的优点集中了起来。基本的思路是使用原型链继承原型上的属性和方法,而通过盗用构造函数继承实例属性。这样既可以把方法定义在原型上以实现重用,又可以让每个实例都有自己的属性。

function Animal(name) {
    this.name = name
    this.colors = ['black', 'white']
}
//把方法定义在原型上
Animal.prototype.getName = function() {
    return this.name
}

function Dog(name, age) {
    Animal.call(this, name)
    this.age = age
}
Dog.prototype =  new Animal()
// 修改Dog的构造器 
Dog.prototype.constructor = Dog 

let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog2) 
// { name: "哈赤", colors: ["black", "white"], age: 1 }

寄生式组合继承

组合继承已经相对完善了,但还是存在问题,它的问题就是调用了 2 次父类构造函数,第一次是在 new Animal(),第二次是在 Animal.call() 这里。
所以解决方案就是不直接调用父类构造函数给子类原型赋值,而是通过创建空函数 F 获取父类原型的副本。
寄生式组合继承写法上和组合继承基本类似,区别是如下这里:

- Dog.prototype =  new Animal()
- Dog.prototype.constructor = Dog

+ function F() {}//获取父类原型的副本
+ F.prototype = Animal.prototype
+ let f = new F()
+ f.constructor = Dog
+ Dog.prototype = f


function object(o) {
    function F() {}
    F.prototype = o //把父类的原型赋值给空函数
    return new F()//此时F()就是父类的原型对象  new F()创建父类的实例(复制一份父类原型)
}
function inheritPrototype(child, parent) {
    let prototype = object(parent.prototype) //获取父类原型对象
    prototype.constructor = child
    child.prototype = prototype
}
inheritPrototype(Dog, Animal)


//这种方式也可以
+ Dog.prototype =  Object.create(Animal.prototype)
+ Dog.prototype.constructor = Dog

clss继承

class Animal {
    constructor(name) {
        this.name = name
    } 
    getName() {
        return this.name
    }
}
class Dog extends Animal {
    constructor(name, age) {
        super(name) //调用父类的构造器
        this.age = age
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值