【延伸学习】TS(JS)类的继承(prototype、call、apply,extends)

这篇具有很好参考价值的文章主要介绍了【延伸学习】TS(JS)类的继承(prototype、call、apply,extends)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

PS:文末附上完整的代码(是在CocosCreator下运行的)

一. 基(父)类  

//----------------------------- 狗 -----------------------------//
// “狗”类的构造函数
function Dog(name, age){
    this.name = name
    this.age = age
    this.luckyNumber = [1,2,3]
}

// 类方法,有点像静态方法,不用创建对象,用类名直接调用的方法
Dog.eat = function(){
    console.log("dog eat")
}

// 通过原型设置狗的两个原型方法
Dog.prototype.showName = function(){
    console.log("dog - name = ", this.name)
}

Dog.prototype.showAge = function(){
    console.log("dog - age = ", this.age)
}

console.log("--------------------- 狗-测试 ---------------------")
var dog = new Dog("lucky", 18)
Dog.eat()
dog.showName()
dog.showAge()
console.log("dog info = ", dog.name, dog.age)

【延伸学习】TS(JS)类的继承(prototype、call、apply,extends),CocosCreator引擎源码分析,javascript,call,prototype,寄生式继承,组合继承,原型模式,extends

基类包含三个成员变量(名字、年龄)还有一个后面用于测试的数组,两个原型方法(输出名字,输出年龄),还有一个类似静态函数的方法。

基类唯一测试的,就是用类名可以直接调用eat这个静态方法。

二. 继承原型方法-通过遍历prototype

//----------------------------- 狗-比熊 -----------------------------//
// 比熊的构造函数
function Dog_BX(){
    this.new_name = "bixiong"
}

// 使用原型来继承方法【写法1】
Dog_BX.prototype = {}
for(var i in Dog.prototype){
    Dog_BX.prototype[i] = Dog.prototype[i]
}

Dog_BX.prototype.showName = function(){
    console.log("dog_bx name = ", this.new_name)
}


console.log("--------------------- 比熊-测试 ---------------------")
var bx_Dog = new Dog_BX()
bx_Dog.showName()
bx_Dog.showAge()
console.log("bx_dog info = ", bx_Dog.name, bx_Dog.age, bx_Dog.new_name)

【延伸学习】TS(JS)类的继承(prototype、call、apply,extends),CocosCreator引擎源码分析,javascript,call,prototype,寄生式继承,组合继承,原型模式,extends

代码:
1.通过遍历基类的prototype方法,来把基类的原型方法赋值给比熊类,从而实现了方法的继承。
2.通过重写showName的原方法,实现了函数的重载。

输出:
1.showName方法的输出,证实里调用的是子类的showName,重载成功。
2.showAge也调用成功了,调用的是父类的showAge,但由于子类没继承父类的成员变量(更没有赋值了),所以输出的age是未定义。
3.输出结果也同样显示,并没有继承父类的成员变量。

核心结论:
通过遍历prototype再赋值给子类,来实现原型方法上的继承。

三.继承成员变量-通过call

//----------------------------- 狗-萨摩 -----------------------------//
// 萨摩的构造函数
function Dog_SM(age){
    // 使用call继承成员变量【写法1】
    Dog.call(this, "sm", age)
}

console.log("--------------------- 萨摩-测试 ---------------------")
var sm_Dog = new Dog_SM(10)
console.log("is function exist = ", sm_Dog.showName, sm_Dog.showAge)
console.log("sm_Dog info = ", sm_Dog.name, sm_Dog.age)

【延伸学习】TS(JS)类的继承(prototype、call、apply,extends),CocosCreator引擎源码分析,javascript,call,prototype,寄生式继承,组合继承,原型模式,extends

代码:
1.Dog.call,使用call来实现继承父类成员函数的功能。

输出:
1.可以看到父类的原型方法并没有被继承到。
2.父类的成员变量被继承了。

核心结论:
使用call来实现继承父类成员函数的功能。其实大致原理是通过改变this的绑定,调用父类构造函数进行赋值时,把赋值的内容赋到子类的this上,从而实现了继承父类成员函数的功能。

四.通过组合实现完美继承

//----------------------------- 狗-拉布拉多 -----------------------------//
// 拉布拉多构造函数
function Dog_LBLD(age){
    // 使用apply继承成员变量【写法2】
    Dog.apply(this, ["lbld", age])
}

// 使用原型来继承方法【写法2】
var obj = function() {}
obj.prototype = Dog.prototype
Dog_LBLD.prototype = new obj()




console.log("--------------------- 拉布拉多-测试 ---------------------")
var lbld_Dog = new Dog_LBLD(5)
lbld_Dog.showName()
lbld_Dog.showAge()
console.log("lbld_Dog info = ", lbld_Dog.name, lbld_Dog.age)

代码:
1.上面使用了call,这里使用apply,实现了成员变量的继承。
PS:我还没太分得清call和apply的区别,也就一个传可变长参数,一个传数组作为参数……
2.通过把Dog.prototype赋值给obj,再new一个obj给Dog_LBLD实现了原型方法的继承。
PS:为什么要写得这么绕?大致就和深拷贝浅拷贝的原理有关,下文【5】再详述吧。

输出:
简单概括,就是成员变量和原型函数都继承下来了,实现了完美的继承。

核心结论:
分别通过不同的方式组合起来实现了成员变量和原型函数的继承。
虽然标题的“完美”二字只是代表成员变量和原型函数都同时继承下来的意思,但当前这种继承方式应该是避开了浅拷贝的问题了,算是比较好的继承方法了。

PS:上文我写了两种成员变量,两种原型函数的继承法防,都可以选出来组合着使用的。

五.原型链直接继承(不建议这样做)

function Dog_BM(){

}

Dog_BM.prototype = new Dog("BoMei", 9)




console.log("--------------------- 博美-测试 ---------------------")
var bm_Dog = new Dog_BM()
var bm_Dog2 = new Dog_BM()
bm_Dog.age = 10
bm_Dog.luckyNumber.push(4)
bm_Dog.showName()
bm_Dog.showAge()
console.log("bm_dog info = ", bm_Dog.name, bm_Dog.age, bm_Dog.luckyNumber)
console.log("bm_dog2 info = ", bm_Dog2.name, bm_Dog2.age, bm_Dog2.luckyNumber)

【延伸学习】TS(JS)类的继承(prototype、call、apply,extends),CocosCreator引擎源码分析,javascript,call,prototype,寄生式继承,组合继承,原型模式,extends

代码:
1.非常简单的,直接new Dog赋值给prototype

输出:
1.成功调用了父类的showName以及showAge方法,并能显示出name和age两个成员函数来。
2.根据【bm_dog info】显示,也顺利的对age和luckyNumber数组进行修改。
3.这种写法方便时方便,但有个致命的缺点,他对引用的处理是浅拷贝的,可以看到,我们只修改了bm_Dog的luckyNumber数组,添加了4进去,可bm_dog2的luckyNumber数组居然也有4. 所以强烈不建议使用这种方式来做继承。 此处也回应了上文【4】中对prototype的处理为什么要这么绕了。

PS:在【4】中对prototype的处理中,我也尝试过用更简单的处理方法:
Dog_LBLD.prototype = Dog.prototype
这样写更加大错特错,因为这样二者的原型函数就会指向同一个内存,当我在Dog_LBLD里重载showName时,最终发现,连父类Dog的ShowName也被修改了。

核心结论:
写法很简单,缺点很明显,就是通过浅拷贝来做继承,要是成员变量存在引用,修改成员变量时,可能会影响到所有对象的成员变量。

六.寄生式组合继承(最优解)

//----------------------------- 狗-金毛 -----------------------------//
function Dog_JM(age){
    // 使用apply继承成员变量【写法2】
    Dog.apply(this, ["jinmao", age])
}

// 使用原型来继承方法【写法3】
Dog_JM.prototype = Object.create(Dog.prototype)




console.log("--------------------- 金毛-测试 ---------------------")
var jm_Dog = new Dog_JM(5)
jm_Dog.showName()
jm_Dog.showAge()
console.log("jm_Dog info = ", jm_Dog.name, jm_Dog.age, jm_Dog.luckyNumber)

【延伸学习】TS(JS)类的继承(prototype、call、apply,extends),CocosCreator引擎源码分析,javascript,call,prototype,寄生式继承,组合继承,原型模式,extends

容许我说一段废话文学吧……有点气死我了……

文章写到此处,其实前5个例子都是我手打,我都能理解的……最后这第六个例子,我看别的文章里说的,说是做继承的最优解。因为别的文章中有提到一种“组合继承”的方式,需要调用多次父类构造函数,效率不是最优(我以为他说的组合继承就是我【4】里面写得那种……)。用这种寄生式继承能完美解决,而这种方式一个我不理解的地方就是Object.create,我不知道他的实现源码是什么。 所以我就当做他是原型继承我想到的第三种方法……

后来我觉得不能不求甚解,就跑去找Object.create的实现源码,结果发现,Object.create这个方法的内部逻辑就是文章【4】里面原型继承的【写法2】………………  当时我写【4】的时候就觉得很好了,还用“完美继承”来形容……

核心结论:
所以这个方法【6】其实和方案【4】是一模一样的………………

七.extends

//----------------------------- 狗-贵宾 -----------------------------//
class Dog2{
    protected name

    constructor(name){
        this.name = name
    }

    showName = function(){
        console.log("Dog2 name = ", this.name)
    }
}

class Dog_GB extends Dog2{
    private age
    constructor(name, age){
        // 初始化父类构造函数
        super(name)
        this.name = name
        this.age = age
    }

    getName(){
        return this.name
    }

    getAge(){
        return this.age
    }
}

【延伸学习】TS(JS)类的继承(prototype、call、apply,extends),CocosCreator引擎源码分析,javascript,call,prototype,寄生式继承,组合继承,原型模式,extends

代码:
1.父类一个成员变量,一个成员函数,一个构造函数。
2.子类构造函数一定要调用super对父类进行初始化,然后子类新增二个成员函数和一个成员变量。

输出:
1.成功使用了父类的方法。
2.成功使用了子类的方法来获取父类的成员变量,证明成员变量继承成功。

核心结论:
就是用extends来做了一个类的继承测试……

以上就是对继承的全部测试了,下面贴上完全的全部代码:

const {ccclass, property} = cc._decorator;

//----------------------------- 狗 -----------------------------//
// “狗”类的构造函数
function Dog(name, age){
    this.name = name
    this.age = age
    this.luckyNumber = [1,2,3]
}

// 类方法,有点像静态方法,不用创建对象,用类名直接调用的方法
Dog.eat = function(){
    console.log("dog eat")
}

// 通过原型设置狗的两个原型方法
Dog.prototype.showName = function(){
    console.log("dog - name = ", this.name)
}

Dog.prototype.showAge = function(){
    console.log("dog - age = ", this.age)
}

//----------------------------- 狗-比熊 -----------------------------//
// 比熊的构造函数
function Dog_BX(){
    this.new_name = "bixiong"
}

// 使用原型来继承方法【写法1】
Dog_BX.prototype = {}
for(var i in Dog.prototype){
    Dog_BX.prototype[i] = Dog.prototype[i]
}

Dog_BX.prototype.showName = function(){
    console.log("dog_bx name = ", this.new_name)
}

//----------------------------- 狗-萨摩 -----------------------------//
// 萨摩的构造函数
function Dog_SM(age){
    // 使用call继承成员变量【写法1】
    Dog.call(this, "sm", age)
}

//----------------------------- 狗-拉布拉多 -----------------------------//
// 拉布拉多构造函数
function Dog_LBLD(age){
    // 使用apply继承成员变量【写法2】
    Dog.apply(this, ["lbld", age])
}

// 使用原型来继承方法【写法2】
var obj = function() {}
obj.prototype = Dog.prototype
Dog_LBLD.prototype = new obj()

//----------------------------- 狗-博美 -----------------------------//
function Dog_BM(){

}

Dog_BM.prototype = new Dog("BoMei", 9)

//----------------------------- 狗-金毛 -----------------------------//
function Dog_JM(age){
    // 使用apply继承成员变量【写法2】
    Dog.apply(this, ["jinmao", age])
}

// 使用原型来继承方法【写法3】
Dog_JM.prototype = Object.create(Dog.prototype)

//----------------------------- 狗-贵宾 -----------------------------//
class Dog2{
    protected name

    constructor(name){
        this.name = name
    }

    showName = function(){
        console.log("Dog2 name = ", this.name)
    }
}

class Dog_GB extends Dog2{
    private age
    constructor(name, age){
        // 初始化父类构造函数
        super(name)
        this.name = name
        this.age = age
    }

    getName(){
        return this.name
    }

    getAge(){
        return this.age
    }
}

@ccclass
export default class NewClass extends cc.Component {

    onLoad(){
        console.log("--------------------- 狗-测试 ---------------------")
        var dog = new Dog("lucky", 18)
        Dog.eat()
        dog.showName()
        dog.showAge()
        console.log("dog info = ", dog.name, dog.age, dog.luckyNumber)

        console.log("--------------------- 比熊-测试 ---------------------")
        var bx_Dog = new Dog_BX()
        bx_Dog.showName()
        bx_Dog.showAge()
        console.log("bx_dog info = ", bx_Dog.name, bx_Dog.age, bx_Dog.new_name)

        console.log("--------------------- 萨摩-测试 ---------------------")
        var sm_Dog = new Dog_SM(10)
        console.log("is function exist = ", sm_Dog.showName, sm_Dog.showAge)
        console.log("sm_Dog info = ", sm_Dog.name, sm_Dog.age)

        console.log("--------------------- 拉布拉多-测试 ---------------------")
        var lbld_Dog = new Dog_LBLD(5)
        lbld_Dog.showName()
        lbld_Dog.showAge()
        console.log("lbld_Dog info = ", lbld_Dog.name, lbld_Dog.age, lbld_Dog.luckyNumber)

        console.log("--------------------- 博美-测试 ---------------------")
        var bm_Dog = new Dog_BM()
        var bm_Dog2 = new Dog_BM()
        bm_Dog.age = 10
        bm_Dog.luckyNumber.push(4)
        bm_Dog.showName()
        bm_Dog.showAge()
        console.log("bm_dog info = ", bm_Dog.name, bm_Dog.age, bm_Dog.luckyNumber)
        console.log("bm_dog2 info = ", bm_Dog2.name, bm_Dog2.age, bm_Dog2.luckyNumber)

        console.log("--------------------- 金毛-测试 ---------------------")
        var jm_Dog = new Dog_JM(5)
        jm_Dog.showName()
        jm_Dog.showAge()
        console.log("jm_Dog info = ", jm_Dog.name, jm_Dog.age, jm_Dog.luckyNumber)

        console.log("--------------------- 贵宾-测试 ---------------------")
        var gb_Dob = new Dog_GB("guibin", 13)
        gb_Dob.showName()
        console.log("gb_Dog info = ", gb_Dob.getName(), gb_Dob.getAge())
    }
}

全部输出日志:

【延伸学习】TS(JS)类的继承(prototype、call、apply,extends),CocosCreator引擎源码分析,javascript,call,prototype,寄生式继承,组合继承,原型模式,extends文章来源地址https://www.toymoban.com/news/detail-824361.html

到了这里,关于【延伸学习】TS(JS)类的继承(prototype、call、apply,extends)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • js--手写call和apply方法干货注释满满

    我们都知道js中call和apply都是改变this指向的,这篇文章我们一起来实现call和apply的底层吧!我们先来看一下js中的call和apply的用法 一.用法 1.call用法 传递参数逗号分隔 2.apply用法 传递参数为数组 二.手写实现call 1.手写myCall改变this指向 这里this指向已经改变,但是还不可以传递

    2024年02月06日
    浏览(43)
  • Js:apply/call/bind、作用域/闭包、this指向(普通,箭头,JS/Vue的this)

    共同点: apply()、call() 和 bind() 方法 三者作用都是 改变this指向。 接收的第一个参数都是this要指向的对象 区别: apply只有两个参数,第二个参数为数组; call和bind传参相同,多个参数依次传入的; call和apply都是对函数进行直接调用(立即执行),而bind方法不会立即调用函数

    2023年04月08日
    浏览(94)
  • ts的class类的使用与继承, es6新增的class类

    前言:         ts的class类的使用与继承, es6新增的class类。         在ES6中为了更好的把js设计成面向对象的语言的语法特征,提出了class 类,class的本质是函数,类不可重复声明,类定义不会被提升,让js更像面向对象编程的语法。         类名建议大写,在严格要求

    2024年02月05日
    浏览(42)
  • 手写apply、call、bind

    作用:改变this执行,函数立即执行,参数以数组传递 思路:         1、在this新指向的对象上,增加一个函数等于待执行函数         2、去参数         3、执行函数         4、删除增加的函数,返回结果 作用:改变this执行,函数立即执行,参数依次传递 思路:      

    2024年02月06日
    浏览(41)
  • 17 JavaScript 中的call和apply

    17 JavaScript 中的call和apply 对于咱们逆向工程师而言. 并不需要深入的理解call和apply的本质作用. 只需要知道这玩意执行起来的逻辑顺序是什么即可 在运行时. 正常的js调用: 接下来, 我们可以使用call和apply也完成同样的函数调用 apply和他几乎一模一样. 区别是: apply传递参数要求是

    2024年02月11日
    浏览(36)
  • Object.prototype.toString.call个人理解

    有人说,typeof不行吗,的确,typeod可以用来判断部分的变量的类型,但是仅仅是部分罢了。 typeof 无法区别 null 和 {“num”:1} 这两个变量值的类型,正确的类型应该是Null和Object,但是typeof对于它们的输出却都是: 因此,需要一个合适的工具来识别各类变量的变量类型,Objec

    2024年01月24日
    浏览(47)
  • (十六)call、apply、bind介绍、区别和实现

    函数中的this指向是在函数被调用的时候确定的,也就是执行上下文被创建时确定的。在一个执行上下文中,this由 调用者 提供,由 调用函数 的方式来决定。 arguments只在函数(除了箭头函数)中存在的类数组参数对象,储存了我们传入的所有参数。 call(this, 参1, 参2, ...) ,第

    2024年04月23日
    浏览(40)
  • JavaScript类继承extends

    继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。 这个已有的类称为 基类(父类) ,新建的类称为 派生类(子类) 。 JavaScript 类继承使用

    2024年02月13日
    浏览(37)
  • 【JavaScript】Function的祖传方法call与apply

    看了本文您能了解到的知识! 在本篇文章中,将带你了解 什么是call和apply , call和apply的用途 、如何手写 call 和 apply 以及 call 和 apply 的使用场景。 call() 和 apply() 是 JavaScript 中的两个内置方法,用于调用函数并指定函数中的 this 值。 两者的区别是: call() 方法的语法和作用

    2024年02月17日
    浏览(54)
  • Vue:extends继承&组件复用性

            提到extends继承,最先想到的可能是ES6中的class、TS中的interface、面向对象编程语言中中的类和接口概念等等,但是我们今天的关注点在于:如何在Vue中使用extends继承特性。 目录 Vue:创建Vue实例的方式 构造函数方式:new Vue Vue.extend方式 Vue.component方式 render渲染函数方

    2024年02月08日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包