浅谈JavaScript对象与继承


Posted in Javascript onJuly 10, 2016

JavaScript是我在C语言之后接触的第二门编程语言,大一暑假的时候在图书馆找了一本中国人写的JavaScript程序设计来看。那个时候在编程方面几乎还是小白,再加上那本书根本没有提JavaScript的编程机制,又有一些误导性的话,一直以来对JavaScript有很深的误解,认为JavaScript只是一门在浏览器上运行的面向对象语言,值此文来写下JavaScript当中很具有迷惑性和容易误解的地方。当然限于作者水平有限,也没有什么开发经验,所以难免有疏漏之处,还望批评指正。

JavaScript的对象

对象是什么

JavaScript代码当中随处可见new关键字,很容易让人产生误解,认为JavaScript是Java一样是基于类继承的语言。但是事实并非如此,JavaScript当中并没有类,那JavaScript的对象不是类那又是什么呢?某种意义上说,JavaScript的对象就是Python当中的字典(哈希表),其实也就是类似这样的键值对:

me={
  "fisrtName" : "seek",
  "lastName" : "truth" ,
  "getName" : function(){
    return this.firstName+this.lastName; //this相当于指向这个对象的指针
  }
}

这是一个比较有误解性的地方,初次看到时候觉得有点无法理解,但仔细用一用还是觉得合理,我们既可以像Python一样用[]运算符来获取元素,也可以用.操作符来获取元素:

me.firstName // => seek
me["lastName"] //=> truth
me.getName() // => seektruth

new运算符

既然JavaScript当中是没有类的,那么new运算符又是在干什么呢?这是JavaScript设计的最让人误解的地方之一。JavaScript是一门函数式编程语言,JavaScript当中函数是一等公民,JavaScript当中函数也是对象,函数对象在被创建的时候会被添加调用属性,比较坑的是JavaScript函数有两种调用方式,一种是加了new关键字的调用,一种是没有new关键字的调用,前者会返回一个对象,后者会返回return语句当中的内容。考虑下面的一段函数:

function Obj(name){
  this.name=name;
  return name;
}

如果我们用new运算符来调用:

obj = new Obj("seektruth") //obj会是一个对象:{"name": "seektruth"}

如果我们直接调用:

obj = Obj("seektruth") //obj会是一个字符串:"seektruth"

确实设计的挺坑的,我们在调用的时候需要分清楚是否需要使用new,一般来说需要用new关键字来调用的函数会采用大写开头。

还有更坑的是如果返回的返回值是一个对象:

function Obj(name){
  this.name=name;
  return {};
}

这样无论我们是否用new运算符来调用都会返回return语句里的值:

new Obj("seektruth") //=> {}
Obj("seektruth") //=> {}

设计的是什么鬼......

对象继承

原型

前面已经说到过JavaScript当中是没有类的,那JavaScript又是怎么来实现继承的呢?答案是通过原型链。在JavaScript当中,每个对象都会有一个原型,在创建对象的时候,如果不加说明的话,对象继承的原型是Object.prototype,函数对象会继承Function.prototype(Function.prototype继承Object.prototype):

Object.prototype // => {}
Function.prototype // => [Function]

我们可以通过对象的__proto__熟悉来查看对象的原型:

a={}
a.__proto__ // => {}

JavaScript通过指定对象的原型来实现继承,指定对象的原型主要有三种方式,一是在构造函数当中指明原型,二是直接修改对象的__proto__属性,三是利用Object.create函数,下面我们依次来看一看

在构造函数当中指定原型

我们可以在构造函数当中指定对象的原型:

me={
  "firstName" : "seek",
  "lastName" : "truth" ,
  "getName" : function(){
    return this.firstName+this.lastName; //this相当于指向这个对象的指针
  }
}

function Obj(name){
  this.firstName = name;
  this.__proto__ = me; //指定原型为me对象
}

指定了原型之后,我们新建了对象之后就可以访问原型的属性:

obj = new Obj("foo"); // => { firstName: 'foo' }
obj.firstName // => foo
obj.lastName // => truth
obj.getName() // => "footruth"

当访问一个对象的时候,首先会尝试在改对象当中寻找该属性,如果没有就回到原型当中寻找,直到Object.prototype。如果我们在新的对象当中重写了原型当中的属性(方法),那么实际使用的时候我们新写的属性(方法)会覆盖掉原型当中的定义,这有点像基于类的语言的函数重载。

注意如果原型me对象的lastname属性有改变,因为obj对象是在原型当中寻找属性,那么这个obj对象的lastname属性也会改变:

me.lastName = "me"
obj.lastName // => "me"
obj.getName() // => "foome"

直接改变对象的原型

我们也可以直接指定(改变)对象的原型:

obj2 = {}
obj2.__proto__ = me
obj2.firstName // => seek
obj2.lastName // => "me"
obj2.getName() // => "seekme"

使用Object.create函数

尽管说前两种方法可以解决问题,但是这两种写法并不优雅,因为JavaScript并不是基于类的语言,第一写法很容易给人以误解,JavaScript语言精粹的作者Crockford认为new就不应该出现在JavaScript语言当中,而推荐使用Object.create函数来基于原型来创建对象。Object.create函数的用法很简单:

obj3 = Object.create(me) // 以me为原型创建新的对象
obj3.firstName // => seek
obj3.lastName // => "me"
obj3.getName() // => "seekme"

obj3 = Object.create(me) 与obj2 = {};obj2.proto = me是等价的,但是前一种写法更优雅也更易于理解。

总结

JavaScript作为一门基于原型的,函数式的编程语言在设计上有很多优雅与强大之处,但同时又有很多糟粕和坑,正式如此,JavaScript也是被误解最多语言。学习了JavaScript的对象继承机制,感觉自己的水平还是大有长进的。

以上这篇浅谈JavaScript对象与继承就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Javascript日期对象的dateAdd与dateDiff方法
Nov 18 Javascript
不要小看注释掉的JS 引起的安全问题
Dec 27 Javascript
JS实现在Repeater控件中创建可隐藏区域的代码
Sep 16 Javascript
JavaScript学习笔记记录我的旅程
May 23 Javascript
让jQuery与其他JavaScript库并存避免冲突的方法
Dec 23 Javascript
ListBox实现上移,下移,左移,右移的简单实例
Feb 13 Javascript
js实现图片轮播效果
Dec 19 Javascript
jQuery Easyui使用(二)之可折叠面板动态加载无效果的解决方法
Aug 17 Javascript
jquery 中toggle的2种用法详解(推荐)
Sep 02 Javascript
JavaScript 判断一个对象{}是否为空对象的简单方法
Oct 09 Javascript
浅析JS抽象工厂模式
Dec 14 Javascript
vue项目引入Iconfont图标库的教程图解
Oct 24 Javascript
Bootstrap框架下下拉框select搜索功能
Mar 26 #Javascript
Bootstrap轮播插件中图片变形的终极解决方案 使用jqthumb.js
Jul 10 #Javascript
深入浅析JavaScript函数前面的加号和叹号
Jul 09 #Javascript
jQuery回到顶部的代码
Jul 09 #Javascript
jQuery 跨域访问解决原理案例详解
Jul 09 #Javascript
JavaScript跨域调用基于JSON的RESTful API
Jul 09 #Javascript
checkbox 选中一个另一个checkbox也会选中的实现代码
Jul 09 #Javascript
You might like
php中利用str_pad函数生成数字递增形式的产品编号
2013/09/30 PHP
CI(CodeIgniter)框架介绍
2014/06/09 PHP
thinkPHP实现的省市区三级联动功能示例
2017/05/05 PHP
JavaScript 数组运用实现代码
2010/04/13 Javascript
深入理解JavaScript系列(43):设计模式之状态模式详解
2015/03/04 Javascript
利用JavaScript的AngularJS库制作电子名片的方法
2015/06/18 Javascript
jquery实现滑屏大图定时收缩为小banner图片的广告代码
2015/09/02 Javascript
利用HTML5的画布Canvas实现刮刮卡效果
2015/09/06 Javascript
JS中多步骤多分步的StepJump组件实例详解
2016/04/01 Javascript
Bootstrap开发实战之第一次接触Bootstrap
2016/06/02 Javascript
Javascript实现图片不间断滚动的代码
2016/06/22 Javascript
Angular2 (RC5) 路由与导航详解
2016/09/21 Javascript
Bootstrap基本样式学习笔记之图片(6)
2016/12/07 Javascript
微信web端后退强制刷新功能的实现代码
2018/03/04 Javascript
vue 监听屏幕高度的实例
2018/09/05 Javascript
深入剖析JavaScript instanceof 运算符
2019/06/14 Javascript
详解JavaScript中new操作符的解析和实现
2020/09/04 Javascript
[02:36]DOTA2英雄基础教程 斯拉克
2013/11/29 DOTA
[15:35]教你分分钟做大人:天怒法师
2014/10/30 DOTA
[46:25]DOTA2上海特级锦标赛主赛事日 - 4 败者组第五轮 MVP.Phx VS EG第二局
2016/03/05 DOTA
Python 常用string函数详解
2016/05/30 Python
打包发布Python模块的方法详解
2016/09/18 Python
Python基于回溯法子集树模板解决最佳作业调度问题示例
2017/09/08 Python
Python中的单继承与多继承实例分析
2018/05/10 Python
Python实现的简单读写csv文件操作示例
2018/07/12 Python
python opencv 图像边框(填充)添加及图像混合的实现方法(末尾实现类似幻灯片渐变的效果)
2020/03/09 Python
基于opencv的selenium滑动验证码的实现
2020/07/24 Python
简述python&pytorch 随机种子的实现
2020/10/07 Python
HTML5-WebSocket实现聊天室示例
2016/12/15 HTML / CSS
HTML5 Canvas中使用用路径描画圆弧
2015/01/01 HTML / CSS
观看《永远的雷锋》心得体会
2014/03/12 职场文书
装修活动策划方案
2014/08/27 职场文书
党员干部廉洁自律承诺书
2015/04/28 职场文书
python实现自动清理文件夹旧文件
2021/05/10 Python
MyBatis自定义SQL拦截器示例详解
2021/10/24 Java/Android
MySQL数据库实验实现简单数据库应用系统设计
2022/06/21 MySQL