一起扫荡javascript(四)——原生对象的改写,原型及继承
先不看标题,先一起看看下面一个很简单的小例子:
1、实现输入‘dorsey’,输出‘y-e-s-r-o-d’。(倒序加连线)
你可能毫不犹豫的这样写:
const inverted = (str,sym) => {return str.split("").reverse().join(sym);} console.log(inverted("dorsey","-"));
但如果说需要在上一个的基础上使字符串加上一个字符串,比如说在第一个生成的结果的基础上添加一个括号,变成'(y-e-s-r-o-d)',为了使逻辑的模块化分离及低耦合,我们一般都会写成单独的模块,就比如说这个新增的我们只会写另一个函数,比如这样:
const inverted = (str,sym) => {return str.split("").reverse().join(sym);} const add = str => {return "(" + str + ")";} add(inverted("dorsey","-")); // 可能我们最终的调用得这样
看着总有种用着不是很顺手的感觉,对吧?没我们用原生api用得顺手吧?为什么呢?看看split,join等等方法,好像就点啊点啊点啊(链式调用)就OK了。比如说,下面这样调用:
"dorsey".inverted("-").add();
那怎么实现呢?看看下面:
String.prototype.inverted = function (sym) { return this.split("").reverse().join(sym); } String.prototype.add = function () { return "(" + this + ")"; } console.log('dorsey'.inverted("-").add());
很简单对吧?就只是在原生对象下改写增添一下自定义的方法,就很方便的达到目的。
你想想,无论最终的返回值是什么,最终是不是都是几大基本类型?(六大基本类型,symbol不算,这个就是一个符号,做唯一标识用的),或者说,值得我们操作的就剩字符串,数组跟对象了对吧?那如果你在这几大基本类型的原型对象上改写了一些方法(原生对象属性基本都是只读的,只能添加,不支持修改),以后调用时点啊点啊点啊,就达到目的啦,这样的调用方式,是不是看着特别的直观,特别的明朗,特别的爽呢?
实际上链式调用在javascript这门语言中是很广泛的一种方式,jQuery就是很典型的链式调用的库,svg图形库方面的D3.js更是无链式不调用。好吧,扯远了,我们是讨论原生的对象改写,其实js跟其他语言很不同的是,它是一切皆对象,你可能普普通通的看了个var a = "hello world";但是这个a本身就是一个继承自String原生js对象的一个实例,具备String对象原型中所有的属性与方法。这是我们要改写原生对象的真正原因(可以扩充我们想要的功能,jQuery源码里面就有很多扩充出来的方法,当然了它是在$对象下扩充。)
看一下这个扩充是怎么写哈,诸君看代码了,就不再一一解释了。
当然了,改写原生js对象属性坑点重重,写写个人用的小工具可以试试,当然了,现在有symbol,就不会出现命名冲突导致覆盖的问题了,而且写到里面的方法最好也一定要是抽象中的抽象,不拘泥任何基础环境,只要有js解释器就OK,不依赖于任何的业务,就是纯粹到极点的数据类型处理,转化等等,打个比方,基础的一些算法,字符串简化或检验,对象处理,降维啥的就都可以弄进里面,对吧?弄成一个单独的文件。需要的时候引入一下这个模块,这样用起来就很方便了= =
比如扩充一个日期格式化:
我们在浏览器一起看一下:
这样是不是就很方便了?用起来跟原生的一样爽对吧?
值得注意的是,原生对象的prototype是只读的,普通对象的prototype则是可读可写的,这个需要注意一下,比如说你这样写:
浏览器会直接给你报错:
既然提到了读写权限,也顺便提下js实际上有提供给我们配置读写权限的能力,你看看下面的方式:
(其实就是vue的根本之一,set与get方法)
在属性的前面加入关键字get,这样你再去设置f0,比如这样:
是无法再修改fn0的值的,另外如果你是在严格模式下呢,它还会报错:
而对于现在基本都是ES6语法转义后的代码(默认都是严格模式),这样写都会报错。
上面是改写了,其实多多少少都涉及到原型及继承:
它是怎样的呢?js跟其他语言不同在于它实际上是没有类这种概念的,你说class不是吗?只能说它是模拟出来的,就是一个个的对象。而要描述这千千万万个对象之间的关系,其实我的理解就是三个字——吸血鬼。卧槽,怎么跟吸血鬼又扯上关系了呢?emmmm...成千上万的吸血鬼实际上就是吸血鬼祖先他们一家子不断的做初拥而诞生的。当然主角他们也一样,吸血鬼祖先是杀不死的(只有当初他们那颗白栎树树枝能杀死),某个吸血鬼祖先真正死去的话,她/他那一脉的所有吸血鬼都得死,这是这个故事的一个小细节,而这个细节在我看来就跟js一样,js对象再多,它实际上都有一个祖先,那就是原生的Object对象,这个原始创造的对象是怎么来的我们先不管,只要知道实际上无论我们做什么操作实际上都是从这个对象new出去一个分支,甚至很多时候我们只是从这个对象的某个分支再new 出去的一个分支。而这就构成了一个js世界,也就是吸血鬼世界。
而原型,emmmm...prototype? __proto__?对于prototype可以理解成API,而__proto__是大多数浏览器提供给我们可以在浏览器查看原型的属性的一个按钮。嗯就是一个下拉菜单。
而原型链呢?就想吸血鬼世界,某个吸血鬼再叛逆,再讨厌他的祖先,但他始终还是他祖先直接或间接创造出来的。追根溯源到最后,还是Object,他的祖先具备的基础能力(吸血),初拥他的直接者的能力(prototype),他自己学习的能力(人为扩充)等等都是可以在这一条链条中找到的,是一系列的纽带,这是我理解中的原型链,可以帮我们追踪定位。比如说达蒙不听话了,嗯,找到他的祖先,你给教育一下= =好吧扯远了。
那继承呢?实际上上面已经说了,他祖先的基础能力,他的直接者的能力都不是他需要去考虑的,生出来就有的,而这就是继承出来的,而想要达到继承后又各自独立,那肯定是只是继承了基因嘛!(原型,抽象),蛋白质啥的还是需要后天去补充的(数据,实体)。这就是继承。
嗯,好了,关于这块的话,暂时想到这些,以后有想到什么的,我再来补充了。
共同学习,写下你的评论
评论加载中...
作者其他优质文章