【JavaScript高级】继承

一、继承

继承是面向对象语言中最显著的一个特征。

它是从已有的类中派生出新的类,新的类能吸收已有类(基类、父类)的数据(特征和行为),并拓展属于自己的新的能力。

原生JavaScipt案例合集
JavaScript +DOM基础
JavaScript 基础到高级
Canvas游戏开发

类:具有相同特征和行为的集合。

比如:人类有姓名、年龄、性别、身高、体重等属性,吃饭、睡觉、走路等等行为,所以人可以划为一类。

人类这个大的范围太广了,我们还可以进行细分,根据不同的划分标准可以划分出不同的小类:

​ 按照肤色:黄种人 白种人 黑种人

​ 按照国籍:中国人、法国人、美国人、俄罗斯等

​ 按照工种:教师、学生、医生、工人、农民等等

​ …

在传统的JS中不存在类的概念,我们使用构造函数模拟类,并通过一些方式实现类与类之间的继承。

对象:从类中拿出的具体特性和行为的个体。

比如:张三丰 年龄23 性别男 黄种人 国籍中华人民共和国 是一个医生

类和对象关系:

​ 类是对象的抽象化;

​ 对象是类的具体化。

传统JS中提供了几种继承的方式:类式继承(原型继承)、构造函数式继承(apply和call方法)、组合式继承(前面两种组合)、寄生式继承(类式继承的优化)、寄生组合式继承(寄生继承和组合继承的结合)

1.1 类式继承

类式继承也叫原型继承,将子类的原型指向父类实例化对象。

//定义父类
function People(name,age,sex){
    this.name = name;
    this.age = age;
    this.sex = sex;
}

People.prototype.eat = function(){
    return "是人就得吃饭,持不同的饭,长不同的身体!!"
}

//定义一个子类
function Doctor(name,age,sex,hospital,des){
    this.name = name;
    this.age = age;
    this.sex = sex;

    this.hospital = hospital;
    this.des = des;
}


//子类的原型 指向 父类的原型
// Doctor.prototype = People.prototype;
//子类的原型 指向 父类的实例化对象
Doctor.prototype = new People();
//子类改变原型指向后 原型链发生紊乱  需要手动修正
Doctor.prototype.constructor = Doctor;
//改变子类的原型后 再去通过原型自定义新的方法
Doctor.prototype.sleep = function(){
    return "是人就得睡觉!管他睡觉打呼噜还是流口水..."
}

//通过父类和子类分别实例化对象
var f = new People("张三丰",123,"男");
var doc = new Doctor("扁鹊",1000,"男","春秋蔡国","扁鹊见蔡桓公,望闻问切");

观察上面控制台信息,还是有一些地方需要优化:

​ 子类的构造函数指向了父类需要优化为指向子类自己的构造函数(上面代码中解决);

​ 父类和子类有一些共同的参数,需要优化;

​ 原型中有空的参数undefined需要优化。

1.2 构造函数式继承

构造函数式继承也叫对象冒充继承。利用 apply 和 call 方法

//定义父类
function Animal(name,age){
    this.name = name;
    this.age = age;
}

Animal.prototype.sayHi = function(){
    return "动物名称:" + this.name + ",动物的年龄:" + this.age;
}

//定义子类
function Bird(name,age,des){
    //利用apply或call改变调用对象
    Animal.apply(this,arguments);

    this.des = des;
}

Bird.prototype.fly = function(){
    return "我想飞的更高..."
}

var bird = new Bird("鹧鸪鸟",4,"我是一只小小小鸟,怎么飞也飞不高!!");

这种方式对 父类和子类有一些共同的参数,进行了优化;

当调用父类原型中的方法时,报错。

说明,这种方式不是真正的继承。

但是,如果是在父类函数中自带的本地属性和方法,可以直接调用。

1.3 组合式继承

原型继承 + aplly继承

//定义父类
function Animal(name,age){
    this.name = name;
    this.age = age;

    this.sayHello = function(){
        return "动物是多种多样,猜我是谁!!!";
    }
}

Animal.prototype.sayHi = function(){
    return "动物名称:" + this.name + ",动物的年龄:" + this.age;
}

//定义子类
function Bird(name,age,des){
    //利用apply或call改变调用对象
    Animal.apply(this,arguments);

    this.des = des;
}

//子类的原型指向父类的实例
Bird.prototype = new Animal();
//修正构造函数
Bird.prototype.constructor = Bird;

Bird.prototype.fly = function(){
    return "我想飞的更高..."
}

var bird = new Bird("鹧鸪鸟",4,"我是一只小小小鸟,怎么飞也飞不高!!");

这种方式解决的问题:父子类参数相同问题,实现真正的继承可以调用父类原型中的方法。

依旧存在的问题:在实例化对象的原型上,存在空的属性。

1.4 寄生式继承

封装一个函数,解决原型上空参数问题。

//定义父类
function Animal(name,age){
    this.name = name;
    this.age = age;
}

Animal.prototype.sayHi = function(){
    return "动物名称:" + this.name + ",动物的年龄:" + this.age;
}

//定义子类
function Bird(name,age,des){
    this.name = name;
    this.age = age;

    this.des = des;
}

//定义一个函数
function extend(F,S){
    var Fn = function () {  };
    Fn.prototype = F.prototype;
    S.prototype = new Fn();
    S.prototype.constructor = S;
}
extend(Animal,Bird);

Bird.prototype.fly = function(){
    return "我想飞的更高..."
}

var bird = new Bird("鹧鸪鸟",4,"我是一只小小小鸟,怎么飞也飞不高!!");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-23tjXSOd-1692924565703)(JavaScript中的继承.assets/image-20210220153309416.png)]

解决的问题:空参数

依旧存在的问题:父子参数重复

1.5 寄生组合式继承

这是我们建议的最终形态,优化程度较高。

//定义父类
function Animal(name,age){
    this.name = name;
    this.age = age;
}

Animal.prototype.sayHi = function(){
    return "动物名称:" + this.name + ",动物的年龄:" + this.age;
}

//定义子类
function Bird(name,age,des){
    Animal.call(this,name,age);

    this.des = des;
}

//定义一个函数
function extend(F,S){
    var Fn = function () {  };
    Fn.prototype = F.prototype;
    S.prototype = new Fn();
    S.prototype.constructor = S;
}
extend(Animal,Bird);

Bird.prototype.fly = function(){
    return "我想飞的更高..."
}

var bird = new Bird("鹧鸪鸟",4,"我是一只小小小鸟,怎么飞也飞不高!!");

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tff8isPI-1692924565703)(JavaScript中的继承.assets/image-20210220153325867.png)]

优化了:空参数问题 父子重复参数的问题

1.6 ES5中 Object.create() 对继承的优化

//定义父类
function Animal(name, age) {
    this.name = name;
    this.age = age;
}

// 父类原型中的方法
Animal.prototype.sayHi = function () {
    return "动物名称:" + this.name + ",动物的年龄:" + this.age;
}

//定义子类
function Bird(name, age, des) {
    // Animal.call(this, name, age);
    Animal.apply(this, arguments);
    this.des = des;
}

// ES5中 Object.create(obj) 优化继承
Bird.prototype = Object.create(Animal.prototype); //基于 Animal 的原型实例的对象

// 原型继承会造成结构的紊乱,将原型对象的构造函数手动改回到 Bird
Bird.prototype.constructor = Bird;

// 子类原型中的方法
Bird.prototype.fly = function () {
    return "我想飞的更高..."
}

var bird = new Bird("鹧鸪鸟", 4, "我是一只小小小鸟,怎么飞也飞不高!!");

1.7 ES6中的类和继承

// 通过关键字class定义父类 Animal
class Animal {
    // 构造函数,参数为对象的属性
    constructor(props) {
        this.name = props.name || 'Unknown';
        this.age = props.age || 'Unknown';
    }
    // 父类中的共有方法
    sayHi() {
        return "动物名称:" + this.name + ",动物的年龄:" + this.age;
    }
}

// 定义子类,并通过关键字extends继承父类
class Bird extends Animal {
    // 构造函数
    constructor(props, nativeAttri) { //props是继承过来的属性,nativeAttri是子类自己的私有属性
        // 通过关键字super调用实现父类的构造函数,相当于获取父类的this指向
        super(props);
        // 子类的私有属性
        this.species = nativeAttri.species;
        this.des = nativeAttri.des;
    }
    // 子类的私有方法
    fly() {
        return "我想飞的更高..."
    }
}

// 实例化 Bird 对象
var bird = new Bird({
    name: "鹧鸪鸟",
    age: 23
}, {
    species: "鸟类",
    des: "我是一只小小小鸟,怎么飞也飞不高!!"
})

控制台操作

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BusJNRz2-1692924565704)(JavaScript中的继承.assets/image-20210220172350618.png)]

1.8 拓展:构造函数中的拷贝继承

把父类的所有属性和方法,拷贝进子类

// 定义一个父类的构造函数
function Animal() {
}

// 把Animal所有不变的属性,都放到它的prototype对象上
Animal.prototype.species = "动物";

// 父类原型中的方法
Animal.prototype.sayHi = function () {
    return "动物名称:" + this.name + ",动物的年龄:" + this.age;
}

//定义子类
function Bird(name, age, des) {
    this.name = name;
    this.age = age;
    this.des = des;
}

// 拷贝继承(浅拷贝):把父对象的所有属性和方法,拷贝进子对象
function extend(Child, Parent) {
    // 获取父子构造函数的原型
    var p = Parent.prototype;
    var c = Child.prototype;

    // 遍历父构造函数原型的属性,并将其拷贝到子构造函数的原型上
    for (i in p) {
        c[i] = p[i]
    }

    //为子对象设一个uber属性,这个属性直接指向父对象的prototype属性
    c.uber = p;//uber是向上、上一层的意思,相当于在子对象上打开一条通道,可以直接调用父对象的方法;这句话只是为了实现继承的完备性,纯属备用性质
}
extend(Bird, Animal);

// 实例化一个Bird对象
var bird = new Bird("鹧鸪鸟", 4, "我是一只小小小鸟,怎么飞也飞不高!!");

不同于直接继承父构造函数的prototype
直接继承父构造函数的prototype,这时改变子构造函数的prototype会引发父构造函数原型的改动。
因为对象属于复杂数据类型,而复杂数据类型的赋值是引用的赋值,跟简单数据类型的赋值是不一样的。
而拷贝之后修改子构造函数原型不会引发父构造函数原型的变化。

三、内置构造函数

3.1 宿主环境所提供的构造函数

宿主环境就是 JS 代码执行的环境,目前所谓的宿主环境其实是浏览器环境

Image对象

var img = document.createElement(“img”);
var img = new Image();


### 3.2 ECMAScript核心语法提供的构造函数

Object    Array   String    RegExp    Date   Function  Number    Boolean   

// Object对象
// var obj = {};
// var obj = new Object();
var obj = Object();

//Array
// var arr = [];
// var arr = new Array();
var arr = Array();

//RegExp
// var patt = /[\u4e00-\u9fa5]/g;
// var patt = new RegExp(/[\u4e00-\u9fa5]/,“g”);
// var patt = new RegExp(“[0-9]”,“g”);
var patt = RegExp(/[0-9]/,“g”);

// Date
var date = new Date();//Tue May 19 2020 15:09:19 GMT+0800 (中国标准时间) “object”
// var date = Date();//“Tue May 19 2020 15:08:54 GMT+0800 (中国标准时间)” “string”

// String
// var str = “hello”; //“string”
// var str = new String(“hello”); //“object”
var str = String(“hello”); //“string”
var arr = str.split(“”);// (5) [“h”, “e”, “l”, “l”, “o”]
/**

  • var str = String(“hello”);
  • var str2 = new String(str);
  • str2.split(“”)
  • 调用完成返回切割的数组,移除str2
  • */

// Number
// var num = 10;
var num = Number(‘10’);//“number”
// var num = new Number(‘10’);//“object”

// Boolean
// var flag = true;
// var flag = Boolean(undefined);//“boolean”
var flag = new Boolean(undefined);//“object”

// Error
// var error = new Error(“除数不能为0”);
var error = Error(“除数不能为0”);

// Function
// var fn = function(){};//ƒ (){}
// function fn(){}// ƒ fn(){}
// var fn = new Function();//ƒ anonymous(){}
// var fn = Function();//ƒ anonymous(){}

//含有参数和返回值
// var fn = new Function(“a”,“b”,“c”,“return a + b + c”);
//等价于
// var fn = function(a,b,c){
// return a+b+c;
// }

// 返回一个对象 需要的是JSON串格式
var fn = new Function('return ’ + ‘{“name”:“张三丰”,“age”:23}’);
//等价于
// var fn = function(){
// return {
// name:“张三丰”,
// age:23
// }
// }

//总结:Object、Array、RegExp、Error、Function是安全类



### 3.3 内置构造函数之间的关系

JS中除了undefined之外所有的东西都可以看作是对象,函数也是对象;

所有的对象又都可以看作是构造函数Object的实例,Object构造函数也是函数;

所有的函数又是Function的实例;

var fn = new Function();
var arr = [];
var obj = new Object();

console.log(fn instanceof Function);//true
console.log(fn instanceof Array);//false
console.log(fn instanceof Object);//true

console.log(fn.constructor);//ƒ Function() { [native code] }
console.log(fn.constructor instanceof Function);//true
console.log(fn.constructor instanceof Object);//true

console.log(Function instanceof Function);//true
console.log(Function instanceof Object);//true

console.log(arr instanceof Array);//true
console.log(arr instanceof Function);//false
console.log(arr instanceof Object);//true
console.log(arr.constructor instanceof Object);//true
console.log(arr.constructor instanceof Function);//true

console.log(obj instanceof Object);//true
console.log(obj.constructor instanceof Object);//true
console.log(obj.constructor instanceof Function);//true
``

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 《JavaScript高级程序设计》(第三版)是一本经典的JavaScript技术书籍。此书由Nicholas C. Zakas撰写,涵盖了广泛的主题,适合有一定JavaScript基础的读者。本书详细介绍了JavaScript语言的各个方面,包括基本语法、DOM操作、BOM操作、事件处理、Ajax、浏览器兼容性问题等。 这本书的优点之一是作者对JavaScript的深刻理解和独特的教学方法。他将复杂的概念和技术变得简单易懂,通过实际的例子和案例来解释和演示。读者可以通过跟随书中的练习和项目,逐渐提升自己的JavaScript编程能力。 此外,本书还包含了一些高级主题,如函数、闭包、面向对象编程等。这些主题对于想要深入理解JavaScript的读者来说十分有价值。此外,作者还介绍了一些最佳实践和优化技巧,帮助读者编写更高效、可维护的JavaScript代码。 《JavaScript高级程序设计》(第三版)最大的优点之一是其综合性。它涵盖了JavaScript的各个方面,并且通过详细的目录、索引和附录,方便读者在需要时进行查找和参考。此外,书中还有大量的实例代码和详细的解释,使得读者能够更好地理解和应用所学的知识。 总结来说,《JavaScript高级程序设计》(第三版)是一本非常全面、详尽的JavaScript技术书籍。它不仅适合有一定基础的读者,也适合那些想要深入了解JavaScript编程的人。无论是作为学习教材还是作为参考书,这本书都是非常有价值的。阅读本书将有助于读者提升自己的JavaScript编程能力,并掌握一些高级技术和最佳实践。 ### 回答2: 《JavaScript高级程序设计(第三版)》是一本经典的JavaScript编程指南,由著名的JavaScript专家尼古拉斯·泽卡斯(Nicholas C. Zakas)撰写。该书自2009年首次出版以来,一直被广泛用作学习JavaScript的参考书籍。 这本书从基础知识讲起,逐渐引导读者深入了解JavaScript的各个方面。作者详细介绍了JavaScript的语法、数据类型、运算符、函数、对象、数组等核心概念,并通过大量的实例和案例进行讲解,帮助读者理解和应用这些知识。 《JavaScript高级程序设计(第三版)》特别关注JavaScript高级特性和最佳实践。作者深入浅出地讲解了闭包、原型链、作用域链等概念,并详细探讨了JavaScript的错误处理、异步编程和模块化等重要主题。读者通过学习这些内容,可以编写出更加高效、可维护和可扩展的JavaScript代码。 此外,书中还介绍了如何在浏览器环境和服务器环境中使用JavaScript,包括DOM操作、事件处理、Ajax、Web存储等技术。作者还对跨浏览器兼容性进行了讨论,帮助读者解决在不同浏览器中遇到的兼容性问题。 总之,《JavaScript高级程序设计(第三版)》是一本非常全面和权威的JavaScript学习资料。它适合初学者学习JavaScript的基础知识,也适合有一定经验的开发者深入了解和掌握JavaScript高级特性。无论是前端开发还是后端开发,读者都能从中获得宝贵的经验和知识。 ### 回答3: 《JavaScript高级程序设计》(第三版)是一本经典的JavaScript编程教材。该书由Nicholas C. Zakas撰写,对JavaScript的核心概念和高级技术进行了深入讲解。 该书主要分为三个部分。第一部分介绍了JavaScript语言的基础知识,包括语法、数据类型、流程控制、函数等内容。这一部分的目的是帮助读者建立对JavaScript基础的扎实理解,为后续的高级概念打下基础。 第二部分是该书的核心内容,讨论了JavaScript的面向对象编程和浏览器环境中的DOM操作。读者将学习使用构造函数、原型和继承等概念来开发复杂的JavaScript应用程序。此外,本书还给出了大量的示例代码和实践项目,帮助读者提升编程实战能力。 第三部分则涵盖了一些高级主题,如错误处理、数据存储、正则表达式、Ajax等。这些议题是现代Web开发中非常重要的部分,对于提升网页交互性和用户体验至关重要。 《JavaScript高级程序设计》(第三版)在内容上更为详尽全面,适合具备一定JavaScript基础的读者学习。此外,该书侧重于实践应用,深入浅出地讲解了一些复杂的概念,并通过实例和项目帮助读者学以致用。 总的来说,该书通过系统性的介绍和练习,帮助读者逐步掌握JavaScript的核心概念和高级技术,为他们成为出色的JavaScript开发者奠定坚实的基础。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

MagnumHou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值