时间杀死的烂俗人(程序媛)

1,860 阅读3分钟

1 start

凌晨准备下班的时候,我刷了一下微博,看见裴先生写下了一段这样的话:

“我生平第二次有了想要结婚的念头。有个人冷暖一直都在我身边,今天她急性阑尾住院了,我才发现我的心会为了她而变得惊心动魄。”

文下有九宫格的照片,那个女人站在樱花树下卖萌,在埃菲尔铁塔前比心,北海道滑雪,还有病床上面无血色的样子。

我没有太惊讶,只是把每张照片都放大了看,我想把那个陌生女人的脸完完全全的记住。

所以,她真的很完美。否则,裴先生怎么会陪她逛遍了整个世界。

我的裴先生啊!你最终还是没有等我。 你的生命中最终还是出现了那个能陪你浪迹天涯,不论霓虹、无惧现实,坦荡荡的陪你走下去的人。

我记得裴先生的备忘录里一共有8条:

1、她爱吃樱桃,笑起来很甜。 -- 算法题解出来的时候

2、她喜欢独当一面,也需要小鸟依人。-- 遇到不会的技术难题

3、她笑得再甜,走得再倔,也别觉得她就不是水做的。-- 写不出代码分分钟哭给你看

4、男人不该情绪化,保护她,相信她,支持而不要支配她。-- 不要在她工作的时候逼她去做别的事情

5、做她的大地,别做她的天。-- 做不了天,她能把天的网络黑到你怀疑人生

6、她喜欢浪漫,可浪漫不是一切,懂她,比陪她浪漫重要。 -- 你就是要懂得一个程序媛的基本素养

7、爱她吧,永远都不用说服自己。 -- 因为除了可爱,其它根本说服不了自己。

8、如果前7条不成立,那一定是你阻止她写代码了!

是啊!我就躺在裴先生的备忘录里,幸福了整个盛夏光年。


「裴先生,我给你出道题好伐?」

「来!」

「那你实现一下数组的一些方法呗!例如push、pop

「…… 噢,晚上我做饭。」

「喂,喂!你都不试一下! 我给你些提示……」

push 方法的底层实现

先来看看ECMA官网push的描述。 image.png

我们把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 方法的底层实现

image.png

「诺,我们直接用代码翻译就好。」

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
  PerformSet(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).
  PerformDeletePropertyOrThrow(O, index).
  PerformSet(O, "length", newLen, true).
  Return element.
  
  隔行如隔山,我真的不会。

这是ECMApop 方法的实现描述。 原来裴先生……

end

WechatIMG7.jpeg

浦东机场,裴先生迟迟不肯领登机牌。裴先生就在机场大厅杵着,红着眼盯着女孩。

女孩主动吻了裴先生,再没有留恋,转身走出了大厅。

女孩记得,她给裴先生的包里留了张便签。

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。 裴先生,我放过你,去飞吧。

窗外凉风吹过,又惊醒了伏在案前的加班狗。

我摸了摸眼角,我好像哭过了。梦里,我陪着裴先生在北海道滑雪,听巴黎圣母院的钟声,看芬兰的极光。

裴先生,你也放过我了。

真俗。