万字长文深度剖析面向对象的javascript(三)

简介: 万字长文深度剖析面向对象的javascript(三)

继承


构造函数的继承


构造函数的继承第一步是在子类的构造函数中,调用父类的构造函数,让子类实例具有父类实例的属性。


然后让子类的原型指向父类的原型,这样子类就可以继承父类原型。


function Person (){
    this.name = 'person';
}
function Boy(){
    Person.call(this);
    this.title = 'boy';
}
Boy.prototype= Object.create(Person.prototype);
Boy.prototype.constructor=Boy;
Boy.prototype.getTitle=function (){console.log(this.title)};
var b =new Boy();
b.getTitle();
console.log(b);
~~
调用父类的构造函数是初始化实例对象的属性。子类的原型指向父类的原型是为了基础父类的原型对象的属性。
另外一种写法是Boy.prototype等于一个父类实例:
~~~js
Boy.prototype = new Person();


上面这种写法也有继承的效果,但是子类会具有父类实例的方法。有时,这可能不是我们需要的,所以不推荐使用这种写法.


JavaScript 不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能:


function Person1 (){
    this.name = 'person';
}
function Person2 (){
    this.sex = '男';
}
function Boy(){
    Person1.call(this);
    Person2.call(this);
    this.title = 'boy';
}
//继承Person1
Boy.prototype= Object.create(Person1.prototype);
//继承链加上Person2
Object.assign(Boy.prototype,Person2.prototype);
Boy.prototype.constructor=Boy;
Boy.prototype.getTitle=function (){console.log(this.title)};
var b =new Boy();
b.getTitle();
console.log(b);
//Boy { name: 'person', sex: '男', title: 'boy' }


class


ES6 的class可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已.


class Person {
    constructor(name,sex) {
        this.name=name;
        this.sex =sex;
    }
    toString(){
        return this.name + ' '+ this.sex;
    }
}


构造函数的prototype属性,在ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。


上面的类等同于:


Person.prototype = {
       constructor(name,sex) {
        this.name=name;
        this.sex =sex;
    }
    toString(){
        return this.name + ' '+ this.sex;
    } 
}


表达式属性名


class还支持动态的表达式属性名:


let methodName = 'getName';
class Person {
    constructor(name,sex) {
        this.name=name;
        this.sex =sex;
    }
    toString(){
        return this.name + ' '+ this.sex;
    }
    [methodName](){
        return this.name;
    }
}


静态方法


类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。


class Person {
    constructor(name,sex) {
        this.name=name;
        this.sex =sex;
    }
    static getSex(){
        return '男';
    }
}
console.log(Person.getSex()); //男
let  p  = new Person();
console.log(p.getSex());//TypeError: p.getSex is not a function


静态属性


静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性.


class Person {
    constructor(name,sex) {
        this.name=name;
        this.sex =sex;
    }
}
Person.address ='address';
console.log(Person.address);


目前,只有这种写法可行,因为 ES6 明确规定,Class 内部只有静态方法,没有静态属性.


class的继承


class的继承一般使用extends关键字:


class Boy extends Person{
    constructor(name,sex,address) {
        super(name,sex); //调用父类的构造函数
        this.address =address;
    }
    toString() {
        return super.toString();//调用父类的方法
    }
}


在子类的构造函数中,只有调用super之后,才可以使用this关键字,否则会报错。这是因为子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例。


super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。


super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。


上面的例子,我们在子类Boy中的toString普通方法中,调用了super.toString(),之前我们也讲了,类的所有方法都定义在类的prototype属性上面。所以super.toString就是Person中定义的toString方法。


由于super指向父类的原型对象,所以定义在父类实例上的方法或属性,是无法通过super调用的。


定义在父类实例上的方法或属性就是指在constructor中定义的方法或者属性。


Person类,在constructor中定义了name属性。我们看一下在Boy中的普通方法中访问会有什么问题:


class Boy extends Person{
    constructor(name,sex,address) {
        super(name,sex); //调用父类的构造函数
        console.log(super.name);  //undefined
        console.log(this.name);  //hanmeimei
        this.address =address;
    }
    toString() {
        return super.toString();//调用父类的方法
    }
    getName(){
        console.log(super.name);  //undefined
        console.log(this.name);    //hanmeimei
    }
}
var b =new Boy('hanmeimei','女','北京');
b.getName();


总结



JS中的面向对象主要有构造函数,原型链,类三种方式,希望大家能够喜欢。

相关文章
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(三)
深入JS面向对象(原型-继承)
90 0
|
JavaScript 前端开发 Java
深入JS面向对象(原型-继承)(一)
深入JS面向对象(原型-继承)
120 0
|
设计模式 JavaScript 前端开发
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
JavaScript的继承机制基于原型链,它定义了对象属性和方法的查找规则。每个对象都有一个原型,通过原型链,对象能访问到构造函数原型上的方法。例如`Animal.prototype`上的`speak`方法可被`Animal`实例访问。原型链的尽头是`Object.prototype`,其`[[Prototype]]`为`null`。继承方式包括原型链继承(通过`Object.create`)、构造函数继承(使用`call`或`apply`)和组合继承(结合两者)。ES6的`class`语法是语法糖,但底层仍基于原型。继承选择应根据需求,理解原型链原理对JavaScript面向对象编程至关重要
278 7
【JavaScript】深入浅出JavaScript继承机制:解密原型、原型链与面向对象实战攻略
|
开发框架 JavaScript 前端开发
JavaScript框架比较与选择:技术深度剖析
【7月更文挑战第23天】选择正确的JavaScript框架是项目成功的关键。React.js、Vue.js、Angular和Svelte等前端框架各有千秋,分别适用于不同的项目需求。同时,Node.js及其后端框架为服务器端开发提供了强大的支持。开发人员应根据项目的复杂性、性能要求、开发周期以及团队技能等因素综合考虑,选择最适合的框架。随着技术的不断发展,未来还将涌现更多优秀的JavaScript框架,为开发者带来更多选择和可能性。
|
前端开发 JavaScript
前端 JS 经典:Class 面向对象
前端 JS 经典:Class 面向对象
83 1
|
存储 JavaScript 前端开发
深度剖析JavaScript中的变量世界:概念、用例与避坑指南
【4月更文挑战第3天】探索JavaScript变量:了解var、let、const的差异,掌握数据类型、用例及避免错误的策略。声明变量时注意作用域和可变性,如var的函数作用域,let和const的块级作用域。理解基本数据类型(Number、String等)和对象类型。示例包括用户输入、计算、控制流程和函数参数。警惕未声明、作用域混淆、类型不匹配和未初始化的错误,遵循最佳实践,如明确命名、避免冗余和适时复用,利用类型检查工具提升代码质量。
338 1
|
JavaScript 前端开发
JavaScript 原型链继承:掌握面向对象的基础
JavaScript 原型链继承:掌握面向对象的基础
|
JavaScript 前端开发 API
在Node.js上使用dojo库进行面向对象web应用开发
请注意,虽然这个例子在Node.js环境中使用了Dojo,但Dojo的许多功能(例如DOM操作和AJAX请求)在Node.js环境中可能无法正常工作。因此,如果你打算在Node.js环境中使用Dojo,你可能需要查找一些适用于服务器端JavaScript的替代方案。
124 0
|
JSON JavaScript 前端开发
深入JS面向对象(原型-继承)(四)
深入JS面向对象(原型-继承)
98 0
|
设计模式 JavaScript 前端开发
深入JS面向对象(原型-继承)(二)
深入JS面向对象(原型-继承)
108 0