我对原型对象中this的一个懵懂错误认识

我对原型对象中this的一个懵懂错误认识

by zhangxinxu from http://www.zhangxinxu.com
本文地址:http://www.zhangxinxu.com/wordpress/?p=2976

一、关于学习的吐槽

有时候,吐槽的东西比技术本身更受用!

我的学习分三个大方向:一是云游四海,集百家之言;二是邯郸学步,依葫芦画瓢;三是磨刀霍霍向猪羊。

1. 云游四海,集百家之言
这也分为三个方向:一是国外有彩头的前端站点;二是微博上晃荡出来的A文B文;三是个人站点订阅以及一些UED团队订阅。

① 国外站点
如下截图,我留作备忘的,谁整理来着?不记得了,对不住这位小哥了,宣传你的机会给丢了~~
我对原型对象中this的一个懵懂错误认识_第1张图片

可惜1天只有24小时,除去拉屎吃饭睡觉觉、把妹聊天瞎闹闹,所剩时间有限的很,不可能把所有文章都细读。因此,大部分文章快思维,知其大概;少部分文章很有兴趣,可以慢思维,这需要集中注意力,劳力伤神,也慎用。还有,英文很重要,前端技术文章颠来倒去就那些词,看多了,自然就速度了。

② 瞎晃悠
在一般的工作模式下,我隔三差五就去微博晃悠。一来是享受各种扑面而来的杂七杂八的信息;二来catch一些关键字、或nice文章,工具链接等。

看似晃悠,也能接触很多对工作学习有用的信息,所谓寓教于乐,似乎就有这种味道。例如最近折腾过的uglifyjs以及Opera回流测试工具都是在微博上瞎晃悠出来的。

其实上班闲晃没什么不好,只要有颗随时把学习放在心上的敏锐的心就好!

③ 订阅
唉,我现在订阅看得少了,因为……丫的更新太不勤快了,很多站点基本上就废掉了,还有的迁移到国外去了。估计是有家室了,给孩子换尿布太花时间了;或者因为新西兰奶粉太贵,赚外快去了!

一些团队UED博客,啧,很多也都废了,有点年把都不更新了,貌似盛大,搜狐之类就是这样。“可见一斑”这个词真是太那个应景了,淘宝UED估计是更新最勤快的,看人家公司的发展……

2. 邯郸学步,依葫芦画瓢
模仿没什么不好。当我们还是小白的时候,模仿是最好的学习方式,到了一定境界,自然有机会形成自己的风格。我的绘画,以及写作都是这么来的,从模仿开始。

话说这模仿的对象很重要。什么北大青鸟之流的都是毒害初学者的,因为这些人一开始“模仿”的东西就是坨褐色的冰淇淋。多去看看jQuery等优秀JS框架的书写,这个东西绝对靠谱。

然而,每天不学点东西,就想撞墙的学霸毕竟少数。如果你让你的下手:“最近没什么活,你去把jQuery的源码看看。”你觉得会发生什么?
拿我自己举例,如果让我去做这些事情,我是会download jQuery测试版js, 然后打开之;然后看到洋洋洒洒,大气磅礴的代码,我会立马感受到我在宇宙中的渺小;即使硬着头皮精读部分语句,也因“不是我不爱攀登,只因前山名叫珠穆朗玛”放弃之……

因此,纯粹去看jQuery源码是不实际的。如何做?寻找兴趣点,逐个击破之。比方说,我想知道一个DOM元素上的CSS值,咋办,咋实现?貌似用到getComputedStyle,具体怎么操作呢?此时,查看jQuery源码~,很赞的选择。千万不要去网上copy那些蛋疼菊紧害人的代码,虽然有功能,但是,书写啊命名啊等实在不敢恭维,当然,喜欢给自己挖坑的人随意。

就我而言,我经常会有这样那样的idea, 我想实现这个,我想试试那个,于是,果断尝试之,遇到或没有遇到问题,我都会参考优秀的JS源代码,这让我学到了很多东西,因为这些毕竟是团队贡献的世界级的产品。

③ 磨刀霍霍向猪羊
拿刀上阵砍猪羊,指定就是实战,实际项目。这是另外的不可或缺的学习与历练,知识的巩固提升,感性认知的升华。然而,单纯的实践经验往往是狭隘的,单纯做项目、不利用业余时间学习的人,最后只会变成自我感觉良好,实际战斗力只有5的渣子。

二、我想构建一个Hash方法

我想构建一个Hash方法,什么时候有这个想法的呢?不记得了,可能是悠哉拉翔的时候,也可能是浑噩瞌睡的时候~~对自己的学习有什么用呢?我也不知道,只是觉得一番揣摩下来,应该会有所收获~~

Hash为何物?
在MooTools框架中,HashArray, Number, Function等并成为原生类。
我对原型对象中this的一个懵懂错误认识_第2张图片

说穿了就是在原生object对象上的封装,MooTools的其他原生类都是在原生对象上做的扩展(这其实是糟糕的),唯独这个Hash,有封装,object还是那个纯洁的object. 原因可能是object为造物主转世,不好在他身上扎刺。//zxx: 猛然想起一个冷笑话——一个绣花针在公交车站伸手拦下了一只刺猬。

用法如下:

var obj = { a: 0, b: "1"}
    , myHash = new Hash(obj);

这个myHash保留了原生object 的所有特性,同时有N多其他扩展,例如each方法(遍历),hasValue方法(检测是否有某值), map方法(都懂的),以及我比较喜欢的toQueryString方法(对象转为查询字符串)等。在实际处理的时候,很好用的。

我对实现没兴趣
这种想法不仅对用户如此,对于同行之间也是这样;人们总是乐于接受表面的、可以快速思维、不损耗精力的事情。因此,我是不会愚蠢到简单的代码秀,分享自己一点所学显然更有简单畅快之感。

三、这是个完整的故事

一个完整的故事会有起因,经过以及结果,我对对象字面量中this的认识也是如此。

1. 事情的起因
平时接触的都是下面的故事:

var story = {
    progress: "unknown",
    start: function() {
        this.progress = "start";
    }
};

然后如下执行的时候,结果就是:

story.start();
console.log(story.progress);

结果

将故事中标红的this改成story,结果也是一样的:

var story = {
    progress: "unknown",
    start: function() {
        story.progress = "start";
    }
};

story.start();
console.log(story.progress);

结果

因此,很自然而然的,在理解上,我就会将this等同于story,也就是this等于这个对象本身
我对原型对象中this的一个懵懂错误认识_第3张图片

//zxx: ① 实际上this并不能完全等同于story。如下例子:
我对原型对象中this的一个懵懂错误认识_第4张图片
结果就是”unknown“. //zxx: 此时window.progress为”start”;

而执行story.progress = "start";的结果则依然是:”start“.
我对原型对象中this的一个懵懂错误认识_第5张图片
我对原型对象中this的一个懵懂错误认识_第6张图片

2. 事情的经过
如下,很简单的几行原型相关的代码:

var Story = function() {};
Story.prototype = {
    progress: "unknown",
    start: function() {
        this.progress = "doing";
    }
};

var myStory = new Story();
myStory.start();
console.log(myStory.progress); // doing

结果是doing不难知道,关键在认识上。

prototype这东西有点像屌丝过滤器,不解释。
我刚接触原型概念的时候,被一堆解释搅得就像被抛弃在北京的雾霾天气里,不仅看不见方向,还胸闷!那种感觉就像是在步行街上遇到还没参加超女的张含韵,我不认识她,她也不认识我。

后来,生搬硬套,囫囵吞枣,也能用用:搞些扩展啊,继承啊什么的。然而多浮于表面,虽专门花了功夫去深入理透,但因大雾过于磅礴,依然理不清啊!这种感觉就像是张妹子参加超女红了,我认识她,她却不认识我,但是我仍能感受其表面的风采。

如果以上面这种状态理解为何结果为”doing“,可能自己那个未经深入思考的理解就是错误的。

我的错误理解
我以为,当执行了myStory.start();的时候,相当于这个:

progress: "unknown", → this.progress = "doing";
↓
progress: "unknown" "doing",
↓
myStory.progress = "doing"; 

图片示意就是:
我对原型对象中this的一个懵懂错误认识_第7张图片

骚年,不要开小差啊,上面的示意是错误的.错误的..错误的…..

错误的理解源于“故事的开始” – 普通对象字面量中的this这样理解很说得通的;以及对原型浮于表面的肤浅认知(有很多的感性成分)。

如何发现错误的?
所谓“实践出真知”,一点不假。如果整天睡在冻床上不知冷热,你则会——————变成小龙女!

我着手构建一个通过new构造的哈希方法(Hash)(本文part2),其中,有个很方法,叫做has, 用来检测对象是否有某关键字(键值对中的键)(不包括原型中的)。其实本质上就是hasOwnProperty方法。

例如上面那个myStory实例,继续下面的检测代码:

console.log(myStory.hasOwnProperty("progress")); 
console.log(myStory.hasOwnProperty("start")); 

我对原型对象中this的一个懵懂错误认识_第8张图片

结果是什么呢?请选择
true, true
true, false
false, true
false, false

按照我之前的错误认识,结果应该是两个false. 而实际上,结果是true, false.

显然,自己的理解是有错误的,而且现在看来,这种错误的理解是很低级与SB的。

错误在哪里?
一句话:原型中的this不是指的原型对象,而是调用对象。

换个通俗的解释。Story是个儿子模板,Story.prototype是共同的爸爸。爸爸中的this并不是指的爸爸本人,而是未来某个new出来的儿子。

套上myStory相关代码解释就是:
myStory是个复制的儿子,老爸中的this指的就是这个儿子,因此当myStory.start();执行后,myStory多了个值为"doing"progress属性。 老爸还是老爸那个样子。

this.progress = "doing"; → myStory.progress = "doing";

想想也是这样啊:老爸肯定是不能变的,否则,复制出来的其他儿子岂不都跟着基因突变,残疾弱智之类。何来继承!

三、故事的结果

就跟电影电视剧一样,需要一点波折才好看(韩剧那种揪心来揪心去的就算了)。故事的结果是什么呢?一个小白,冲破了一道门槛,前方之路立马变得平坦。哈哈,喜剧,鼓掌鼓掌

所谓“平坦”指的是?
1. this的解释确实是那样
例如,对String原型扩展的一个过滤HTML代码方法:

String.prototype.stripHTML = function() {
    return this.replace(/<(?:.|\s)*?>/g, "");
};

显然,this指的是字符串本身的啦,怎么可能是原型呢!哈哈~~

2. 以前的一些迷糊开朗了
哦,原来jQuery中的继承以及包装器this也是这么个套路~~
我对原型对象中this的一个懵懂错误认识_第9张图片

原来,

var myArray = new Array();

也是这个套路,原本:

Array.prototype = { ... }

Array原型方法中的this实际上就是指的myArray啦,与上面的myStory一个套路。所以明白了,

Array.prototype.slice.call(arguments);

是个怎么回事了,argumentscallthis,指代为类似myArray的数组被返回,哈哈,明白啦,明白啦!

这就是我“邯郸学步”学出的一点东西。现在的我感觉就像是知道了张妹子其实就是个普通的妹子,不温不火,有时候生活可能比自己还苦逼,且圈子太复杂,很难遇到俺们这些根正苗红、品性纯良的好男人,唉,只能祝福了!

四、结语,略溅口水

巴拉巴拉这么多,一篇技术文章写出了散文的味道,“哈啾”,sorry,有点感冒了~

本文内容其实总结一下很简单。

  1. 我是这么学习的……
  2. 我最近用了其中一个方法学习……
  3. 我用这个方法学习发现了我之前一个错误的认识……
  4. 啊哈,我学到了东西。你呢?

我在海边撒贝壳,各种颜色,各种形状。于是,你可能喜欢这个,他可能喜欢那个,或者另外极品不喜欢贝壳。

JS资质有限,如果文中有什么理解错误的,务必指正,误人子弟可是大大的罪过啊,阿门阿门!

感谢阅读,欢迎交流。

我擦,忘记了一个重要的东西。上面所提到的折腾的Hash方法扩展,您有兴趣可以狠狠地点击这里查看:hash.js

有个各个方法的测试demo,您有兴趣可以狠狠地点击这里查看:hash.html
demo打开后,右键页面查看源代码,啦啦啦啦啦~~~

原创文章,转载请注明来自张鑫旭-鑫空间-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=2976

你可能感兴趣的:(web,javascript)