Javascript继承,再谈

说到Javascript的继承,相信只要是前端开发者都有所了解或应用,因为这是太基础的知识了。但不知各位有没有深入去理解其中的玄机与奥秘。今本人不才,但也想用自己的理解来说一说这其中的玄机和奥秘。

一、类继承的发展吏

  • function实现的继承

function的继承是完全模仿了OOP的编程思想。实现的是类的继承

  • object.create实现的继承

用object.create来修改其原型

  • es6的继承

增加了class来模拟OOP的继承实现。上述两种继承实现,他都还是支持的。

二、各时期类继承的实现

  • function继承方式的实现(OOP)
function Animate(name){
    this.name = name;
}
Animate.prototype.getName = function(){
    return this.name;
}

function Dog(name){
    Animate.apply(this,arguments);
    this.leg = 4;
}
Dog.prototype = Inherit(Animate, Dog);
Dog.prototype.say = function(){
    return ‘wang‘;
}

//function模式的继承
function Inherit(parent, child){
    //创建一个无原型方法的类
    function f(){}
    f.prototype = parent.prototype; //将父对象的原型赋给临时对象
    f.prototype.constructor = child; //将子类构造函数绑定到 临时对象的 prototype原型上,保持子类构造函数与prototype上的一致。
    return new f(); //执行了f的构造函数,而没有执行prototype.constructor指向的构造函数
} 

var dog = new Dog(‘dog‘);
console.log(‘getName:‘ + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( ‘dog instanceof Animate:‘ + (dog instanceof Animate)); //true
console.log( ‘dog instanceof Animate: ‘ + (dog instanceof Dog)); //true

OOP方式的继承实现网上有很多种,如:原型链,实现、组合、寄生组合继承等。上述实现为寄生组合继承在,算比较通用且完美的一种方案了。

  • object.create实现继承
    这是一个升级版本的类式继承,需要了解object.create方法。Object.create(proto, [propertiesObject]),其中proto是新创建对象的原型对象,而propertiesObject是可选的,要添加到新创建对象的可枚举属性(即其自身定义的属性,而不是原型链接上的属性)。
    我们还需要了解的方法:Object.setPrototypeOf(内部原型的写方法);Object.getPrototypeOf(内部原型的读方法)。内部原型:[[prototype]] == proto
    上述继承代码的改造后
function Animate(name){
    this.name = name;
}
Animate.prototype.getName = function(){
    return this.name;
}

function Dog(name){
    Animate.apply(this,arguments);
    this.leg = 4;
}
Inherit(Animate, Dog); //调用点改造
Dog.prototype.say = function(){
    return ‘wang‘;
}
//继承实现方法改造
function Inherit(parent, child){
    child.prototype = Object.create(parent.prototype); //create实现parent上的原型复制
    child.prototype.constructor = child; //将构造函数指回子类
} 

var dog = new Dog(‘dog‘);
console.log(‘getName:‘ + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( ‘dog instanceof Animate:‘ + (dog instanceof Animate)); //true
console.log( ‘dog instanceof Animate: ‘ + (dog instanceof Dog)); //true

2.1 对prototype的尝试

上述示例中用了Object.create方法创建一个对象,然后再赋值给Prototype,而为什么不用Object.setPrototypeOf方法直接改变其Prototype的值呢。原因摘录来源于MDN:

由于现代 JavaScript 引擎优化属性访问所带来的特性的关系,更改对象的 [[Prototype]]在各个浏览器和 JavaScript 引擎上都是一个很慢的操作。其在更改继承的性能上的影响是微妙而又广泛的,这不仅仅限于 obj.proto = ... 语句上的时间花费,而且可能会延伸到任何代码,那些可以访问任何[[Prototype]]已被更改的对象的代码。如果你关心性能,你应该避免设置一个对象的 [[Prototype]]。相反,你应该使用 Object.create()来创建带有你想要的[[Prototype]]的新对象。

对象继承的实现:

var animate = {
    name: "name"
};
Object.setPrototypeOf(animate,{
    getName: function(){
        return this.name;
    }
});

var dog = {
    leg: 4
};
Object.setPrototypeOf(dog,{
    say: function(){
        return ‘wang‘;
    }
});
Object.setPrototypeOf(Object.getPrototypeOf(dog),Object.getPrototypeOf(animate));

console.log(‘getName:‘ + dog.getName()); //dog
console.log("say:" + dog.say()); //wang

三、ES6类继承的实现

es6对类继承提供了原生的支持,这让Javascript更像后端语言了,简单使用如下:

class Animate{
    constructor(name){
        this.name = name
    }
    getName(){
        return this.name;
    }
}

class Dog extends Animate{
    constructor(name){
        super(name);
        this.leg = 4;
    }
    say(){
        return "wang";
    }
}
var dog = new Dog(‘dog‘);
console.log(‘getName:‘ + dog.getName()); //dog
console.log("say:" + dog.say()); //wang
console.log( ‘dog instanceof Animate:‘ + (dog instanceof Animate)); //true
console.log( ‘dog instanceof Animate: ‘ + (dog instanceof Dog)); //true

四、总结及疑问

经过本文梳理,你是否发现Javascript的类继承实现越来越简单,更接近于Java,.net这类静态编译语言了,或许这就是所谓的万物归一的哲学道理。但在此还是存在一个极大的疑问:Object.setPrototypeOf方法在MDN不建议使用,说是更改内部的[[prototype]]属性存在性能问题 和 影响。不知道其影响为何,望大神们指定

原文地址:https://www.cnblogs.com/cqhaibin/p/8542283.html

时间: 2024-08-29 07:48:32

Javascript继承,再谈的相关文章

再谈javascript图片预加载技术

图片预加载技术的典型应用: 如lightbox方式展现照片,无疑需要提前获得大图的尺寸,这样才能居中定位,由于javascript无法获取img文件头数据,必须等待其加载完毕后才能获取真实的大小然后展示出来,所以lightbox显示的图片的速度体验要比直接输出的差很多,而本文说提到的预加载技术主要针对获取图片尺寸. 一段典型的使用预加载获取图片大小的例子: var imgLoad = function (url, callback) {    var img = new Image();   

我看朴灵评注阮一峰的《JavaScript 运行机制详解:再谈Event Loop》

阮一峰和朴灵对我来说都是大牛,他们俩的书我都买过,阮老师的译作<软件随想录>和朴灵的<深入浅出node.js>.这个事情已经过了4个月了,所以我拿来讲应该也没啥问题. 这件事情是这样的,阮一峰在自己的博客写了篇文章<JavaScript 运行机制详解:再谈Event Loop>,然后朴灵看见了,发现了很多问题,然后在印象笔记又写了篇文章<[朴灵评注]JavaScript 运行机制详解:再谈Event Loop>,由于印象笔记现在已经不能访问了(尼玛也太烂了)

浅谈javascript继承【读javascript设计模式第四章节继承有感】

javascript继承,无任是类式继承,原型式继承还是渗元式继承都是通过不同方法去围绕着prototype转,简单分析下三种不同继承方法是如何围绕prototype转的 一:类似继承,先上关键代码 function extend(subClass,supClass){ var fn = function(){}; fn.prototype = supClass.prototype; subClass.prototype = new fn(); subClass.prototype.constr

Java继承之再谈构造器

目录 Java继承之再谈构造器 初始化基类 默认构造器 带参数的构造器 子类调用父类构造器 Java继承之再谈构造器 初始化基类 前面提到,继承是子类对父类的拓展.<Thinking in Java>中提到下面一段话: 当创建一个导出类的对象时,该对象包含了一个基类的子对象.这个子对象与你用基类直接创建的对象是一样的.二者区别在于,后者来自于外部,而基类的子对象被包装在导出类的对象内部. 我们在创建子类对象时,调用了父类的构造器,甚至父类的父类构造器.我们知道,构造器用于创建对象,那么突然产生

[JavaScript]再谈 this

再谈this 关于 this,之前有写一篇文章略微涉及到:就是这里. 当时还没理解得很深入,浅尝辄止的感觉,也没有很全面地总结 this 的指向和用法. 直到我昨晚看到了一篇博文,google搜索 js this 出来的第一篇文章,茅塞顿开,对于 this 有了更直观更全面更细致更清晰的了解!我真希望每一个对 this 感到困惑的朋友可以看到这篇文章,写得很好,感谢这位作者和他的文章. 先列举一下他的观点: 1.如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是wi

再谈angularJS数据绑定机制及背后原理—angularJS常见问题总结

Angular 的数据绑定采用什么机制,详述原理? 脏检查机制.阐释脏检查机制,必须先了解如下问题. 单向绑定(ng-bind) 和 双向绑定(ng-model) 的区别? ng-bind 单向数据绑定($scope -> view),用于数据显示,简写形式是 {{}}. 两者的区别在于页面没有加载完毕 {{val}} 会直接显示到页面,直到 Angular 渲染该绑定数据(这种行为有可能将 {{val}} 让用户看到):而 ng-bind 则是在 Angular 渲染完毕后将数据显示. ng-

C++ Primer 学习笔记_73_面向对象编程 --再谈文本查询示例

面向对象编程 --再谈文本查询示例 引言: 扩展第10.6节的文本查询应用程序,使我们的系统可以支持更复杂的查询. 为了说明问题,将用下面的简单小说来运行查询: Alice Emma has long flowing red hair. Her Daddy says when the wind blows through her hair, it looks almost alive, like a fiery bird in flight. A beautiful fiery bird, he

闲聊javascript继承和原型

javascript继承已经是被说烂的话题了,我就随便聊一点~ 一.javascript的复制继承 javascript的继承有复制继承和原型继承,基于复制继承用的不太多,而且无法通过instanceof的验证 //拷贝继承,prototype.js的extend=> function extend(destination,source){ for(var property in source) destination[property]=source[properyt]; return des

javascript继承—prototype属性介绍(2)

js里每一个function都有一个prototype属性,而每一个实例都有constructor属性,并且每一个function的prototype都有一个constructor属性,这个属性会指向自身.这会形成一个非常有意思的链式结构.举例如下: function Person(){ this.name =12; } console.log(Person.prototype); console.log(Person.prototype.constructor);//输出Person,指向自身

一种基于ES5的JavaScript继承

关于JavaScript继承,方式很多,包括compile-to-javascript的语言TypeScript, CoffeeScript以及网站MDN, GitHub, Modernizr各种polyfill都给出了稳妥的实现方案. 从ES5的角度看,这其中一些方案在功能上OK,但在语义上却不尽如人意. 本人从这些方案中采取一些比较潮的思路,整理出一份方案,可实现与原生DOM类继承的风格一致,达到功能和语义兼得的效果(当然,就别再老想着99后ES3了). 如果你的WebApp是基于ES5运行