1 start
凌晨准备下班的时候,我刷了一下微博,看见裴先生写下了一段这样的话:
“我生平第二次有了想要结婚的念头。有个人冷暖一直都在我身边,今天她急性阑尾住院了,我才发现我的心会为了她而变得惊心动魄。”
文下有九宫格的照片,那个女人站在樱花树下卖萌,在埃菲尔铁塔前比心,北海道滑雪,还有病床上面无血色的样子。
我没有太惊讶,只是把每张照片都放大了看,我想把那个陌生女人的脸完完全全的记住。
所以,她真的很完美。否则,裴先生怎么会陪她逛遍了整个世界。
我的裴先生啊!你最终还是没有等我。 你的生命中最终还是出现了那个能陪你浪迹天涯,不论霓虹、无惧现实,坦荡荡的陪你走下去的人。
我记得裴先生的备忘录里一共有8条:
1、她爱吃樱桃,笑起来很甜。
-- 算法题解出来的时候2、她喜欢独当一面,也需要小鸟依人。
-- 遇到不会的技术难题3、她笑得再甜,走得再倔,也别觉得她就不是水做的。
-- 写不出代码分分钟哭给你看4、男人不该情绪化,保护她,相信她,支持而不要支配她。
-- 不要在她工作的时候逼她去做别的事情5、做她的大地,别做她的天。
-- 做不了天,她能把天的网络黑到你怀疑人生6、她喜欢浪漫,可浪漫不是一切,懂她,比陪她浪漫重要。
-- 你就是要懂得一个程序媛的基本素养7、爱她吧,永远都不用说服自己。
-- 因为除了可爱,其它根本说服不了自己。8、
如果前7条不成立,那一定是你阻止她写代码了!
是啊!我就躺在裴先生的备忘录里,幸福了整个盛夏光年。
「裴先生,我给你出道题好伐?」
「来!」
「那你实现一下数组的一些方法呗!例如push、pop」
「…… 噢,晚上我做饭。」
「喂,喂!你都不试一下! 我给你些提示……」
push 方法的底层实现
先来看看ECMA官网对push的描述。
我们把1-7点分别用代码实现一下:
Array.prototype.push = function(...items) {
let O = Object(this); // 1: 先转换为对象
let len = this.length >>> 0;
let argCount = items.length >>> 0;
if (len + argCount > 2 ** 53 - 1) { // PS: 2 ^ 53 - 1 为JS能表示的最大正整数
throw new TypeError("The number of array is over the max value")
}
for(let i = 0; i < argCount; i++) {
O[len + i] = items[i];
}
let newLength = len + argCount;
O.length = newLength;
return newLength;
}
可以很直观的看出,给数组本身循环添加新的元素 item,然后将数组的长度 length 改为当前最新的长度,即可完成 push 的底层实现。
「诺,裴先生很简单吧?」
「???」
「那我们在看下reduce的底层实现吧!」
reduce 方法的底层实现
「诺,我们直接用代码翻译就好。」
Array.prototype.reduce = function(callbackfn, initialValue) {
// 异常处理,和 map 类似。 咦,map 好像还没写。
if (this === null || this === undefined) {
throw new TypeError("Cannot read property 'reduce' of null");
}
// 处理回调类型异常
if (Object.prototype.toString.call(callbackfn) != "[object Function]") {
throw new TypeError(callbackfn + ' is not a function')
}
let O = Object(this);
let len = O.length >>> 0;
let k = 0;
let accumulator = initialValue; // reduce方法第二个参数作为累加器的初始值
if (accumulator === undefined) {
throw new Error('Each element of the array is empty');
// 初始值不传的处理
for(; k < len ; k++) {
if (k in O) {
accumulator = O[k];
k++;
break;
}
}
}
for(;k < len; k++) {
if (k in O) {
// 注意 reduce 的核心累加器
accumulator = callbackfn.call(undefined, accumulator, O[k], O);
}
}
return accumulator;
}
「裴先生,你看,说了很容易的吧? 那你要不要把map的底层实现写…… 」
「🥱」
「裴先生,你居然睡着了!?」
……
呲~!
滴滴师傅突然一个急刹车挽回了我的思绪。
这些年,我总是觉得自己强大到,足够去面对这些了,并且百毒不侵。 但这一刻我多么想直面那个女人,告诉她这个男人也曾是我最爱的人。
我以为人是慢慢变老的,其实不是,人是一瞬间变老的。 陪伴,是最长情的告白。我输得不冤。
2 曾经
浦东机场,裴先生出抵达出口,有个女孩一窝蜂的就冲了过去,脑袋撞在他胸口上,发出“砰”的声音。
「哎呦喂,胸口好痛,要谋杀啦!」
『哼,谁让你要这么久。我腿都站酸了!」
「好好好,那你坐在我的拉杆箱上,我推着你。」
『不要!你多幼稚啊,不怕别人笑话你哦?」
「好吧,那你拉箱子,我背你。」
女孩一脸幸福的趴在裴先生背上,仿佛那是世界上最温暖的地方,迷瞪一会儿就睡着了。女孩隐隐约约的听见,裴先生好像说了句什么。
「你这趴着就能睡着的毛病还是没改呐!小心被人贩子拐跑喔!」
女孩脑袋在裴先生背上蹭了蹭,像做梦一样,呢喃着像似梦呓。
「人家才不会告诉你,自从你走之后我就再也没踏实睡过呢。」
再醒来的时候,发现裴先生正背着她在上楼梯,运动鞋踩在阶梯上也能发出“嘭”的声音。哎?我不是刚还在机场么,我的箱子呢?
「吵醒你啦!不要太担心了,箱子我寄存在机场了。马上就到房间了,你再安稳睡一觉。」
背上的女孩明显身子颤了一下。是机场啊,裴先生还是会走的啊!
自裴先生走后,女孩一直没有换住处。裴先生这轻车熟路的样子,倒是给了女孩不少心安。裴先生可能就不走了吧?至少不会那么快就走了吧?
是啊。时间总是麦哲伦,能珍惜当下就已经是最大的奢侈了。女孩贪婪的吸着裴先生身上的气味,脑海中不安的因子慢慢的淡了去。
洗完澡,女孩走出浴室,看见裴先生早已丝毫不顾形象的扒拉在沙发上,鼾声如雷。女孩认不出噗哧一笑,裴先生还是那个裴先生,连睡觉的姿势都和以前一样丑。
女孩给裴先生找来毛毯盖上,发现茶几上贴着一张便签:别瞎想了,这次回来我不打算走了,箱子的问题只是个意外。另外,我会写数组的map方法了。
map 方法的底层实现
Array.prototype.map = function(callbackFn, thisArg) {
if (this === null || this === undefined) {
throw new TypeError("Cannot read property 'map' of null");
}
// 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
if (Object.prototype.toString.call(callbackfn) != "[object Function]") {
throw new TypeError(callbackfn + ' is not a function')
}
let O = Object(this); // 1. Let O be ? ToObject(this value).
let T = thisArg; // 2. Let len be ? LengthOfArrayLike(O).
let len = O.length >>> 0;
let A = new Array(len); // 4. Let A be ? ArraySpeciesCreate(O, len).
for(let k = 0; k < len; k++) { // Repeat, while k < len,
if (k in O) { // 5. Let k be 0.
let kValue = O[k];
// 依次传入this, 当前项,当前索引,整个数组
let mappedValue = callbackfn.call(T, KValue, k, O);
A[k] = mappedValue;
}
}
return A; // 7. Return A.
}
女孩笑着流下了泪水,打湿了那张便签。裴先生一定是上帝赐予自己的最好礼物,上辈子一定是拯救了银河系,这辈子才能遇见裴先生。
3 委屈
裴先生越来越忙了。就周末偶尔陪陪自己,吃饭逛街看电影。大多数时候,裴先生都待在公司。
女孩怕裴先生给自己太大压力,主动安慰到。
「我的裴先生呐,告诉你一个好消息喔!我家里人已经同意我们都婚事了,他们对你印象都很好的。这周末你不要加班,要见家长啦!」
清晨去上班,裴先生刚打开门,女孩就从后背抱住了裴先生。裴先生明显被吓到了,身体都僵硬了。裴先生转过身问到。
「你说什么,你说的是真的?」
女孩用力点点头,裴先生像受了刺激一样,抱起女孩就呼啦呼啦的转圈圈,转得头晕乎乎的。女孩无奈的摸了摸自己的额头,天呐,这哪里是裴先生,这分明就是裴三岁嘛!
周末,裴先生穿好衬衫,买了件休闲西装换上,提着大包小包的礼品就跟着上门件家长了。
自那以后,裴先生就更加疯狂了。工作起来不要命,熬夜胃痛就泡杯咖啡止痛,为了拿额外的加班费,一切节假日都选择加班。
女孩觉得裴先生越来越魔怔了。难道这件事情又给裴先生照成了很大的压力?可是家里人都挺和善的啊!
某天,裴先生回到家,整个人往沙发上一趴,鼾声就震遍了整栋楼。女孩把裴先生手里握着的手机拿出来,发现手机界面还停留在微信公司群的界面。裴先生真的是拼命啊!
女孩正打算关闭手机屏幕,却突然鬼使神差的返回到了手机桌面。女孩知道,裴先生手机里有一款备忘录软件,裴先生经常把一些重要的事情记在上面。
女孩打开那个备忘录,第一页还是那8条,女孩心里美滋滋的往后翻,第2页却写满了令人惊讶的内容。
When the pop method is called, the following steps are taken:
1. Let O be ? ToObject(this value).
2. Let len be ? LengthOfArrayLike(O).
3. If len = 0, then
Perform ? Set(O, "length", +0F, true).
Return undefined.
4. Else,
Assert: len > 0.
Let newLen be F(len - 1).
Let index be ! ToString(newLen).
Let element be ? Get(O, index).
Perform ? DeletePropertyOrThrow(O, index).
Perform ? Set(O, "length", newLen, true).
Return element.
隔行如隔山,我真的不会。
这是ECMA 上pop 方法的实现描述。 原来裴先生……
end
浦东机场,裴先生迟迟不肯领登机牌。裴先生就在机场大厅杵着,红着眼盯着女孩。
女孩主动吻了裴先生,再没有留恋,转身走出了大厅。
女孩记得,她给裴先生的包里留了张便签。
pop 方法的底层实现
// 这是你的`pop`
Array.prototype.pop = function() {
let O = Object(this);
let len = this.length >>> 0;
if (len === 0) {
O.length = 0;
return undefined;
}
len --;
let value = O[len];
delete O[len];
O.length = len;
return value;
}
// 不。这始终只是我的pop。 裴先生,我放过你,去飞吧。
窗外凉风吹过,又惊醒了伏在案前的加班狗。
我摸了摸眼角,我好像哭过了。梦里,我陪着裴先生在北海道滑雪,听巴黎圣母院的钟声,看芬兰的极光。
裴先生,你也放过我了。
真俗。