资讯专栏INFORMATION COLUMN

JavaScript继承的思想实现

PingCAP / 415人阅读

摘要:本质上是摒弃类,不调用构造函数,而是用,直接让新对象继承旧对象的属性。基于类型的继承基于类型的继承是通过构造函数依赖于原型的继承,而非依赖于对象。例如需要通过来访问基类的构造函数继承自。

JavaScript作为一门语法比较松散的语言,在ES6之前并没有像C++/Java等传统OO语言一样有class关键字,也不能通过private,public等关键字来限定权限。本篇就介绍一下JavaScript是如何实现继承的(js的继承说白了只是一种思想上的继承,在代码级别并没有像java的天然继承,在编写js的时候采用oo思想,能更简单的优化和扩展代码)。

JavaScript的继承可以分为两类:
• 基于对象的继承
• 基于类型的继承

基于对象的继承
基于对象的继承也叫原型继承。我们知道通过JavaScript字面量创建的对象都会连接到Object.prototype,因此我们用Object.prototype来实现继承。本质上是摒弃类,不调用构造函数,而是用Object.create(),直接让新对象继承旧对象的属性。例如:

var person = {
    name: "Jack",
    getName: function () { return this.name; }
}
var p1 = Object.create(person);
console.log(p1.getName());    //Jack

代码很简单,person有一个属性和一个方法。对象p1通过Object.create()来继承,第一个参数prototype指向person的prototype,这样对象p1就继承了person的属性和方法。
Object.create()还可以指定第二个参数,即数据属性,将其添加到新对象中。数据属性可设4个描述符value, writable,enumerable,configurable 。后3个看名字也能猜出意思,不指定的话默认为false。因为和本篇关系不大,就不跑题了,只看看设置value的情况:

var p2 = Object.create(person, {
    name: {
        value: "Zhang"
    }
});
console.log(p2.getName());    //Zhang

用Object.create()相当于创建了一个全新的对象,你可以给该对象任意新增,重载它的属性和方法:

var person = {
    name: "Jack",
    getName: function () { return this.name; },
    getAge: function() { return this.age; } //注意并没有age这个成员变量,依赖子类实现
}

var p3 = Object.create(person);
p3.name = "Rose";
p3.age = 17;
p3.location = "上海";
p3.getLocation = function() { return this.location; }

console.log(p3.getName());    //Rose
console.log(p3.getAge());     //17
console.log(p3.getLocation());    //上海

在person中并没有age这个属性,因此你调用person.getAge();将得到undefined。但在对象p3里新定义了age这个属性,于是就能正确地调用基类的getAge方法。另外子类重载了name的值,且新定义了location属性和getLocation方法。结果如上所示,不赘述。

基于类型的继承
基于类型的继承是通过构造函数依赖于原型的继承,而非依赖于对象。例如:

function Person(name) {
    this.name = name;
    this.getName = function () { return this.name; };  
}
function Student(name, age) {
    Person.call(this, name);
    this.age = age;
    this.getAge = function () { return this.age; }; 
}
Student.prototype = new Person();    //需要通过new来访问基类的构造函数

var p = new Person("Cathy");
var s = new Student("Bill", 23);

console.log(p.getName());    //Cathy
console.log(s.getName());    //Bill
console.log(s.getAge());     //23

Student继承自Person。name虽然是在基类Person里被定义的,但用new调用Person的构造函数后,this将被绑定到子类Student对象上,因此name最终是定义在子类Student对象上的。结果如上所示,不赘述。
保护隐私
之所以定义getName,getAge等方法就是不想让用户直接访问name,age等属性。可惜上面两种继承均无法保护隐私,均可像p.name,p.age这样直接访问属性。如果认为这些属性的隐私非常重要,希望模拟出OO语言中private属性的效果,可以用函数模块化。
所谓函数模块化,本质上就是在函数内新建一个对象,新对象的方法里使用参数对象的属性,然后将新对象返回。此时新对象里是没有参数对象的属性的,达到了保护隐私的目的。代码如下:

var person = function(spec) {
    var that = {};        //新对象
    that.getName = function () { return spec.name; };  //使用参数的属性
    that.getAge = function() { return spec.age; };  //使用参数的属性
    return that;        //返回新对象
}

var p4 = person({name: "Jane", age: 20});

console.log(p4.name);    //undefined
console.log(p4.age);     //undefined
console.log(p4.getName());    //Jane
console.log(p4.getAge());     //20

因为函数person返回的是新对象that,而that里并没有name和age属性,因此直接访问会得到undefined。只能通过that暴露出的两个接口来获取name和age。
进一步实现多层继承也非常方便,效果如下,不赘述:

var student = function(spec) {
    var that = person(spec);        //新对象继承自person
    that.getRole = function() { return "student"; };  //新对象增加方法
    that.getInfo = function() {
        return spec.name + " " + spec.age + " " + that.getRole();
    };
    return that;    //返回新对象
};

var p5 = student({name:"Andy", age:12});

console.log(p5.name);       //undefined
console.log(p5.getName());  //Andy
console.log(p5.getRole());  //student
console.log(p5.getInfo());  //Andy 12 student

更多资源上:去转盘;或者加我的QQ群参与js,css的讨论学习(QQ群:512245829)

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80159.html

相关文章

  • javascript高级程序设计》第六章 读书笔记 之 javascript继承6种方法

    摘要:继承的是超类型中构造函数中的属性,如上继承了属性,但没有继承原型中的方法。上述造成的结果是子类型实例中有两组超类型的构造函数中定义的属性,一组在子类型的实例中,一组在子类型实例的原型中。 ECMAScript只支持实现继承,主要依靠原型链来实现。与实现继承对应的是接口继承,由于script中函数没有签名,所以无法实现接口继承。 一、原型链 基本思想:利用原型让一个引用类型继承另一个引用...

    孙吉亮 评论0 收藏0
  • JavaScript 原型中哲学思想

    摘要:而作为构造函数,需要有个属性用来作为以该构造函数创造的实例的继承。 欢迎来我的博客阅读:「JavaScript 原型中的哲学思想」 记得当年初试前端的时候,学习JavaScript过程中,原型问题一直让我疑惑许久,那时候捧着那本著名的红皮书,看到有关原型的讲解时,总是心存疑虑。 当在JavaScript世界中走过不少旅程之后,再次萌发起研究这部分知识的欲望,翻阅了不少书籍和资料,才搞懂...

    sugarmo 评论0 收藏0
  • JavaScript实现继承

    摘要:使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。总结实现继承有种方式原型链继承借用构造函数继承组合继承原型式继承寄生式继承寄生组合式继承寄生组合式继承是大家公认的最好的实现引用类型继承的方法。 简介 本文不准备深入细节,主要是对《JavaScript高级程序设计中》介绍的JS如何实现继承做一个总结,毕竟好记性不如烂笔头。文末会附带一张神图,搞清楚这张图,...

    岳光 评论0 收藏0
  • 再谈JavaScript面向对象思想继承

    摘要:面向对象中有三大特征,封装,继承,多态。这不仅无法做到数据共享,也是极大的资源浪费,那么引入对象实例对象的属性指向其构造函数,这样看起来实例对象好像继承了对象一样。实例对象的原型指向其构造函数的对象构造器的指向。 前言 为什么说是再谈呢,网上讲解这个的博客的很多,我开始学习也是看过,敲过就没了,自以为理解了就结束了,书到用时方恨少啊。实际开发中一用就打磕巴,于是在重新学习了之后分享出来...

    svtter 评论0 收藏0
  • JS对象(1)重新认识面向对象

    摘要:对象重新认识面向对象面向对象从设计模式上看,对象是计算机抽象现实世界的一种方式。除了字面式声明方式之外,允许通过构造器创建对象。每个构造器实际上是一个函数对象该函数对象含有一个属性用于实现基于原型的继承和共享属性。 title: JS对象(1)重新认识面向对象 date: 2016-10-05 tags: JavaScript 0x00 面向对象 从设计模式上看,对象是...

    superw 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<