博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
重新认识JavaScript中的面向对象
阅读量:6236 次
发布时间:2019-06-22

本文共 2572 字,大约阅读时间需要 8 分钟。

本文系读完winter《重学前端》相关章节并查阅相关文档后的学习总结,特此声明和感谢。

误解

以前总觉得JavaScript中的面向对象是一团乱麻,各种原型和类的概念交织错乱,读过的一些书(如《你不知道的JavaScript》)也对JavaScript中类的写法嗤之以鼻以至于不推荐使用新的class关键字。种种现象让我过去很长一段时间都认为JavaScript是一门设计得很差劲的语言,所谓的面向对象都是模拟出来的,虽然我还是得靠它吃饭。

两种面向对象的实现思路

面向对象的思想由于其易理解、可扩展、模块化等优势广为流行,其设计思路可分为两个流派:

  1. 基于类:先定义一个虚拟的分类,如“猫”类,再去实例化具体的猫;分类之间又可形成继承和组合,如继承于“猫”类的“中华田园猫”类,“中华田园猫”类与“公猫”类又可组合为“中华田园公猫”类。
  2. 基于原型:直接定义一只具体的猫,以这只猫为原型,附加或修改一些特性,就出现了一只独具特色的中华田园猫,还可以“照猫画虎”地根据这只猫来定义出各种猫科动物。

很明显的,JavaScript属于第二种基于原型的流派,它本身是一种非常优秀的方案,但由于一些外部原因,JavaScript被额外添加了许多因素用来模拟基于类的流派,这才让它看起来混乱不堪。

基于原型的面向对象

抛开其模拟类的复杂语法,其实JavaScript基于原型的设计非常简单:

  1. 将对象的状态和方法统一为“属性”,它们在Java中被分别称为“属性”和“方法”,在C++中被称为“成员变量”和“成员函数”;
  2. 所有对象都具有私有属性[[prototype]],就是对象的原型;
  3. 访问对象的属性,若对象本身没有,就继续访问其原型、原型的原型等,直到找到此属性或原型为空为止。

ES6中基于原型的语法也非常简明:

  1. Object.create:根据原型创建新对象,原型可以为null;
  2. Object.getPrototypeOf:获取对象的原型;
  3. Object.setPrototypeOf:设置对象的原型。

基于原型的对象示例:

const cat = {    shitOfficer: 'human',    say() {        console.log('meow~');    }}const chineseCat = Object.create(cat);chineseCat.say = function() {    console.log('miao~')}console.log(chineseCat.shitOfficer);    // 'human',访问到原型cat的属性chineseCat.say();   // 'miao~'复制代码

JS早期版本中的模拟类

在JS早期版本中,对于类的支持是相当弱的,主要是通过Function对象和new操作符来模拟类的,主要知识点如下:

  • Function对象的构造器中包含一个prototype属性,它指向从这个构造器构造出的所有对象的原型
  • 使用new操作符时:
    1. 以构造器的prototype指向的对象为原型,创建新对象
    2. 将构造器中的this绑定到上一步创建的对象上,执行构造器(即执行函数)
    3. 若函数没有返回其他对象,则将第一步创建的对象返回
  • 需要实现继承时较为复杂且实现方式多样

示例:

// 使用this:直接在构造器中给this添加属性,使用new操作符后this会绑定到新创建的对象上function fun1() {    this.p1 = '1';    this.p2 = function() {        console.log(this.p1);    }}var obj1 = new fun1();obj1.p2();  // '1'// 使用prototype:给构造器的prototype属性指向的原型对象添加属性function fun2() {}fun2.prototype.p1 = '2';fun2.prototype.p2 = function() {    console.log(this.p1);}var obj2 = new fun2();obj2.p2();  // '2'复制代码

ES6中的类

ES6中引入了新特性class,它实际上还是用之前的原型来实现的,使用class定义的类,其每个实例对象具有同一个原型对象,类中定义的属性都会被写在此原型对象上。 class从语言标准上统一了类的实现方法,使function回归原本的函数语意,同时使用extends关键字可轻松实现继承功能,示例:

class Cat {    constructor(name) {        this.name = name;    }        say() {        console.log(this.name + ': meow~');    }}class chineseCat extends Cat {    constructor(name) {        super(name);    }        say() {        console.log(this.name + ': miao~');    }}const myCat = new chineseCat('Mimi');myCat.say();    // 'Mimi: miao~'复制代码

总结

理解了JavaScript基于原型的设计理念后就会明白,JavaScript中的面向对象并非原先想象中那样混乱不堪。在我看来,相较于基于类的面向对象,基于原型的设计摒弃了所有“虚”的、概念上的东西,一切皆为实体对象,万物皆可追溯至源头,且源头仍是一个实体。 当然,由于一些历史原因,JavaScript被赋予了很多打破自身体系的画蛇添足的东西,就像它的名字中很有误导性的“Java”一样。但既然我们使用的是JavaScript,就应该理解并遵循JavaScript本身的设计理念,发挥它独有的特点,对于一名前端来说尤其如此。

转载于:https://juejin.im/post/5c85bc4a5188257ed47b0e38

你可能感兴趣的文章
Codeforces 452 A. Eevee
查看>>
小鱼儿CTO赵兴国:基于阿里云的互联网+视频会议系统实践
查看>>
基于smack的即时聊天系统之文件传输功能实现
查看>>
Boa服务器的移植
查看>>
Linux网络编程入门
查看>>
help
查看>>
我的友情链接
查看>>
GIT服务器配置及同步站点目录
查看>>
我的友情链接
查看>>
以太坊中的nonce是什么
查看>>
我的友情链接
查看>>
14-9-11 C/C++课程设计--图书馆管理系---<time.h>中时间数据类型的学习记录
查看>>
java环境配置--转载
查看>>
IPAD2 开启手势教程、未越狱
查看>>
WINTEL平板X86国内上市,神舟老总:ipad仅是玩具
查看>>
debian 中文美化
查看>>
实现查询条件文本框、下拉表、复选框页面组装
查看>>
我的友情链接
查看>>
安卓开发中控制台启动adb,总是说adb server is out of date. killing...
查看>>
解决局域网内打印机经常无法正常连接
查看>>