分类
未分类

JavaScript 中你应该知道的 旧习惯 与 新习惯(一)

使用const 或者 let 替代 var

使用const 声明你不打算改变的值,比如配置,比如对象的引用。

使用let 声明打算改变的值

缩小变量的作用域

不用在开头列出所有的变量,现在推荐使用let 或者 const 就近声明,提高代码的可维护性

用块状作用域代替匿名函数

for(var n = 0; n < 10; n++){
    (function(value){
        setTimeout(
        	function(){
                console.log(value);
            },10
        );
    })(n)
}

使用块状作用率代替匿名函数

for(let n = 0; n < 10; n++){
	setTimeout(function(){
        console.log(n);
    })
}

使用箭头函数代替各种访问this值的变通方式

为了回调中访问上下文的this,使用了这些

旧习惯

  • 使用变量,var self = this
  • 使用 bind
  • 在支持的函数中,使用 thisArg 形参

新习惯

使用箭头函数

在不涉及this,或者大多数情况下,箭头函数都可以代替普通函数,更简洁

使用参数默认值,而不是代码实现

旧习惯

function do(参数){
	if(参数 === undefined){	
		参数 = 默认值
	}
    // XXX
}

新的习惯

function do(参数 = 默认值){
	// XXX
}

使用 rest 参数替代 arguments 关键字

旧习惯

function func1(a, b, c) {
  console.log(arguments[0]);
  // expected output: 1

  console.log(arguments[1]);
  // expected output: 2

  console.log(arguments[2]);
  // expected output: 3
}

func1(1, 2, 3);

新习惯

function func1(...rest) {
  console.log(rest[0]);
  // expected output: 1

  console.log(rest[1]);
  // expected output: 2

  console.log(rest[2]);
  // expected output: 3
}

func1(1, 2, 3);

考虑尾后逗号

旧习惯

const temp = {
	a:1,
	b:2
}

新习惯

const temp = {
	a:1,
	b:2,
}

好处在哪尼,问题在修改的时候可以少敲一个逗号

使用类创建构造函数

旧习惯

// 使用传统的函数语法
var Bird = function Bird(name){
   	this.name = name;
}
Bird.prototype.talk = function talk(string){
    return this.name + 'talk:' + string;
}

var bird = new Bird("小红");

bird.talk("Hi!");
// '小红talk:Hi!

新习惯

class Bird{
	constructor(name){
        this.name = name;
    }
    talk(string){
        return this.name + 'talk:' + string;
    }
}
var bird = new Bird("小红");

bird.talk("Hi!");
// '小红talk:Hi!
分类
未分类

从element的一次PR开始

那天我正刷着B站,主页突然跳出来up程序员小山与Bug的视频,名字叫 el-table固定表头滚动时,表头不跟手抖动的问题,跟着学到了一点调试小技巧,和大家分享下。

1、Ctrl + Shift + p 可以召唤出Chrome的命令

可以在里面方便的禁用js脚本

2、github上的 #数字 可以直接在github上的PR那边直接进入

比如

https://github.com/ElemeFE/element/pull/21863

这里的21863 就是编号

同样在releases 的文档种能找到这行

指的就是这个功能的PR号,非常的方便,看别人源码也不容易大海捞针

3、如何简单排查某行代码是否会影响其他功能,如果测试写的好的话直接跑测试,那如果测试不方便或者看不出来尼,可以看下增加那段代码时候的提示,是否是为了解决bug或者新增的功能或者单纯的是提高性能。

然后来看下这个同步是怎么做的

syncPostion() {
       const { scrollLeft, scrollTop, offsetWidth, scrollWidth } = this.bodyWrapper;
       const { headerWrapper, footerWrapper, fixedBodyWrapper, rightFixedBodyWrapper } = this.$refs;
       if (headerWrapper) headerWrapper.scrollLeft = scrollLeft;
       if (footerWrapper) footerWrapper.scrollLeft = scrollLeft;
       if (fixedBodyWrapper) fixedBodyWrapper.scrollTop = scrollTop;
       if (rightFixedBodyWrapper) rightFixedBodyWrapper.scrollTop = scrollTop;
       const maxScrollLeftPosition = scrollWidth - offsetWidth - 1;
       if (scrollLeft >= maxScrollLeftPosition) {
         this.scrollPosition = 'right';
      } else if (scrollLeft === 0) {
         this.scrollPosition = 'left';
      } else {
         this.scrollPosition = 'middle';
      }
    },

其实很简单,获取当前的scrollLeft 赋值给另一个 scrollLeft 就完成了,让我们来写个简单的同步

// index.html
<div class="headerWrapper wrapper">
 <table>
   <colgroup>
     <col width="180">
     <col width="180">
     <col width="200">
     <col width="200">
   </colgroup>
   <thead>
     <tr>
       <th>凉</th>
       <th>风</th>
       <th>有</th>
       <th>信</th>
     </tr>
   </thead>
 </table>

</div>
<div class="bodyWrapper wrapper">
 <table>
   <colgroup>
     <col width="180">
     <col width="180">
     <col width="200">
     <col width="200">
   </colgroup>
   <tbody>
     <tr>
       <td>凉风有信</td>
       <td>秋月无边</td>
       <td>亏我思娇情绪好比度日如年</td>
       <td>恨天各一方难与秋娟再相见</td>
     </tr>
   </tbody>
 </table>

</div>

css

.wrapper{
 width:300px;
 overflow: auto;
}

.wrapper > table{
 width:800px;
 
}
.headerWrapper{
 overflow: hidden;
}

下面就是见证奇迹的时刻

function ready() {

 const headerWrapper = document.getElementById("headerWrapper");
 const bodyWrapper = document.getElementById("bodyWrapper");

 bodyWrapper.addEventListener('scroll', function() {
   window.requestAnimationFrame(() => {
     let top = this.scrollTop
     let left = this.scrollLeft
     headerWrapper.scrollTo(left, top);
  })
})
}

document.addEventListener("DOMContentLoaded", ready);

在线练习链接 https://jsfiddle.net/knightgao/ksbyLfjg/59/

这样就实现了简单的js联动

那更进一步,按照力扣的命名规则,刚刚那题叫联动的话,那下面这题叫联动2

要求是n个互相影响尼,比如给了一排的div,要求拖动其中一个带动所有的进行滚动

1对1 到了 1对 N

原理没变,多了一些要求

  • 避免触发遍历的时候改变自己
  • 避免scroll 事件循环触发

关于循环触发这里补充下

循环触发例子链接 https://jsfiddle.net/knightgao/5L9mkz1t/19/

当test1滚动的时候会设置同步test2的值,如果这时候 test2 scroll 事件 中设置 test1的值,就会导致循环触发,造成不必要的性能浪费

<div class="headerWrapper wrapper">
 <table>
   <colgroup>
     <col width="400">
     <col width="400">
     <col width="400">
     <col width="400">
   </colgroup>
   <thead>
     <tr>
       <th>冲动</th>
       <th>的</th>
       <th>惩</th>
       <th>罚</th>
     </tr>
   </thead>
 </table>

</div>
<div class="bodyWrapper wrapper">
 <table>
   <colgroup>
     <col width="400">
     <col width="400">
     <col width="400">
     <col width="400">
   </colgroup>
   <tbody>
     <tr>
       <td>那夜我喝醉了拉着你的手</td>
       <td>胡乱地说话</td>
       <td>只顾着自己心中压抑的想法</td>
       <td>狂乱地表达</td>
     </tr>
   </tbody>
 </table>
</div>

<div class="bodyWrapper wrapper">
 <table>
   <colgroup>
     <col width="400">
     <col width="400">
     <col width="400">
     <col width="400">
   </colgroup>
   <tbody>
     <tr>
       <td>我迷醉的眼睛已看不清你表情</td>
       <td>忘记了你当时会有怎样的反应</td>
       <td>我拉着你的手放在我手心</td>
       <td>我错误地感觉到你也没有生气</td>
     </tr>
   </tbody>
 </table>
</div>
.wrapper{
 width:600px;
 overflow: auto;
}

.wrapper > table{
 width:2000px;
 
}
.headerWrapper{
 overflow: hidden;
}
function ready() {

 const nodes = document.getElementsByClassName("wrapper");

 function initScroller(nodes) {
   let max = nodes.length
   if (!max || max === 1) return
   let limit = 0;
   nodes.forEach((ele, index) => {
     ele.addEventListener('scroll', function() {
       window.requestAnimationFrame(() => {
         if (!limit) {
           limit = max - 1;
           let top = this.scrollTop
           let left = this.scrollLeft
           for (node of nodes) {
             if (node === this) continue;
             node.scrollTo(left, top);
          }
        } else
           --limit;
      })
    }, {
       passive: true
    });
  });
}
 initScroller([...nodes]);
}

document.addEventListener("DOMContentLoaded", ready);

在线地址 https://jsfiddle.net/knightgao/getb5mpj/24/

同学们下课

分类
未分类

vue-dev-server 源码解析

vue-dev-server 介绍

vue-dev-server是尤大编写的一个小工具,功能一句话介绍

This is a proof of concept.

Imagine you can import Vue single-file components natively in your browser… without a build step.

how it works

  • Imports are requested by the browser as native ES module imports – there’s no bundling.
  • The server intercepts requests to *.vue files, compiles them on the fly, and sends them back as JavaScript.
  • For libraries that provide ES modules builds that work in browsers, just directly import them from a CDN.
  • Imports to npm packages inside .js files (package name only) are re-written on the fly to point to locally installed files. Currently, only vue is supported as a special case. Other packages will likely need to be transformed to be exposed as a native browser-targeting ES module.

我来简单翻译下就是,翻译的不好见谅

  • 没有打包,浏览器直接使用 ES module 导入
  • 服务拦截 *.vue 的文件请求,即时编译,然后返回浏览器对应的 js
  • 对于那些在浏览器提供 ES modules 构建的库来说,只需要从CDN导入
  • 对于vue文件内的 导入 会动态重写用来支持本地安装的那些库

老规矩,看库先看test,站在2022年这个角度,还是很熟悉的用法。

测试比较简单就三个文件: index.html , main.js , test.vue

接着找下 package.json ,看看命令

“bin”: { “vue-dev-server”: “./bin/vue-dev-server.js” },

“scripts”: { “test”: “cd test && node ../bin/vue-dev-server.js” }

也很简单,直接指向了 bin/vue-dev-server.js

#!/usr/bin/env node

const express = require('express')
const { vueMiddleware } = require('../middleware')

const app = express()
const root = process.cwd();

app.use(vueMiddleware())

app.use(express.static(root))

app.listen(3000, () => {
 console.log('server running at http://localhost:3000')
})

这里很好理解起了个服务

中间件 vueMiddleware

设置了 静态文件目录就当前目录

重点看下 vueMiddleware

const vueCompiler = require('@vue/component-compiler')
const fs = require('fs')
const stat = require('util').promisify(fs.stat)
const root = process.cwd()
const path = require('path')
const parseUrl = require('parseurl')
const { transformModuleImports } = require('./transformModuleImports')
const { loadPkg } = require('./loadPkg')
const { readSource } = require('./readSource')

const defaultOptions = {
 cache: true
}

const vueMiddleware = (options = defaultOptions) => {
 let cache
 let time = {}
 
 if (options.cache) {
   const LRU = require('lru-cache')

   cache = new LRU({
     max: 500,
     length: function (n, key) { return n * 2 + key.length }
  })
}

 const compiler = vueCompiler.createDefaultCompiler()

 function send(res, source, mime) {
   res.setHeader('Content-Type', mime)
   res.end(source)
}

 function injectSourceMapToBlock (block, lang) {
   const map = Base64.toBase64(
     JSON.stringify(block.map)
  )
   let mapInject

   switch (lang) {
     case 'js': mapInject = `//# sourceMappingURL=data:application/json;base64,${map}\n`; break;
     case 'css': mapInject = `/*# sourceMappingURL=data:application/json;base64,${map}*/\n`; break;
     default: break;
  }

   return {
     ...block,
     code: mapInject + block.code
  }
}

 function injectSourceMapToScript (script) {
   return injectSourceMapToBlock(script, 'js')
}

 function injectSourceMapsToStyles (styles) {
   return styles.map(style => injectSourceMapToBlock(style, 'css'))
}
 
 async function tryCache (key, checkUpdateTime = true) {
   const data = cache.get(key)

   if (checkUpdateTime) {
     const cacheUpdateTime = time[key]
     const fileUpdateTime = (await stat(path.resolve(root, key.replace(/^\//, '')))).mtime.getTime()
     if (cacheUpdateTime < fileUpdateTime) return null
  }

   return data
}

 function cacheData (key, data, updateTime) {
   const old = cache.peek(key)

   if (old != data) {
     cache.set(key, data)
     if (updateTime) time[key] = updateTime
     return true
  } else return false
}

   // 解析单文件组件
 async function bundleSFC (req) {
     // 读取文件
   const { filepath, source, updateTime } = await readSource(req)
   const descriptorResult = compiler.compileToDescriptor(filepath, source)
   const assembledResult = vueCompiler.assemble(compiler, filepath, {
     ...descriptorResult,
     script: injectSourceMapToScript(descriptorResult.script),
     styles: injectSourceMapsToStyles(descriptorResult.styles)
  })
   return { ...assembledResult, updateTime }
}

 return async (req, res, next) => {
   if (req.path.endsWith('.vue')) {      
       // 处理vue文件 bundle 后返回 javascript
     const key = parseUrl(req).pathname
     let out = await tryCache(key)

     if (!out) {
       // Bundle Single-File Component
       const result = await bundleSFC(req)
       out = result
       cacheData(key, out, result.updateTime)
    }
     
     send(res, out.code, 'application/javascript')
  } else if (req.path.endsWith('.js')) {
       // 处理javascript 文件 使用缓存 提高效率 返回 javascript
     const key = parseUrl(req).pathname
     let out = await tryCache(key)

     if (!out) {
       // transform import statements
       const result = await readSource(req)
       out = transformModuleImports(result.source)
       cacheData(key, out, result.updateTime)
    }

     send(res, out, 'application/javascript')
  } else if (req.path.startsWith('/__modules/')) {
       // 处理 modules 下的路径 尝试缓存 loadPkg 只对 vue 做了处理 返回 javascript
     const key = parseUrl(req).pathname
     const pkg = req.path.replace(/^\/__modules\//, '')

     let out = await tryCache(key, false) // Do not outdate modules
     if (!out) {
       out = (await loadPkg(pkg)).toString()
       cacheData(key, out, false) // Do not outdate modules
    }

     send(res, out, 'application/javascript')
  } else {
     next()
  }
}
}

exports.vueMiddleware = vueMiddleware

到这里基本的解析就完成了,其实做的很简单,

  • 重复利用缓存,减少io
  • 充分的封装,保持主流程的清晰,与主流程无关的都封装出去,转移出去
  • 逻辑清晰,扩展容易,后续要扩展react 也很清楚要在哪里加
分类
未分类

前端拾遗|从前端函数式编程开始

函数式编程是什么呢?是一种编程范式,比较经典的函数式语言有 Haskell ,实际上 JacaScript 本身作为一门多范式的语言也是支持函数式的。

函数式具有五个鲜明的特点:

  1. 函数是一等公民
  2. Lambda表达式
  3. 纯函数,也叫没有副作用,不影响外部变量
  4. 不修改外部状态
  5. 引用透明,只依赖于输入的参数

来看一个例子


const arguments = ['qiupu'];
const callName = name => {
  console.log(arguments[0])
}
const callRealName = function(name) {
  console.log(arguments[0])
}
callName('knight'); // qiupu
callRealName ('knight'); // knight

这就是典型的上下文透传的例子。


数组里有一些方法可以实现类似Lodash库的语句组合形式,如链式调用、函数作为参数调用,也可以做一些控制语句代替for/while等。

来看一个例子

在JSX中我们常常看到这样的用法


const menu = (
<div>
  {
    props.post.filter(item =>item.name).map(item=>{
    return <div key={item.id}>{item.name}<div>
    })
  }
</div>
)

这里常见的map、filter等就是常见的 组合子 的包装。

分类
未分类

vue3变化

vue3的变化

全局api

createApp 返回实例 替代 new Vue 使得返回实例不再共享全局配置 全局的方法也从Vue上转移到了实例上

2.x全局API 3.x实例API(app)
Vue.config app.config
Vue.config.productionTip removed
Vue.config.ignoredElements app.config.isCustomElement
Vue.component app.component
Vue.directive app.directive
Vue.mixin app.mixin
Vue.use app.use
Vue.prototype app.config.globalProperties

config.ignoredElements 就是现在 config.isCustomElement

引入此配置选项旨在支持本机自定义元素,因此重命名可以更好地传达其功能。新选项还期望一个比旧字符串/ RegExp方法具有更大灵活性的函数:

 // before
 Vue.config.ignoredElements = ['my-el', /^ion-/]
    
 // after
 const app = Vue.createApp({})
 app.config.isCustomElement = tag => tag.startsWith('ion-')

Vue.prototype 取而代之 config.globalProperties

在Vue 2中,Vue.prototype通常用于添加所有组件都可以访问的属性。 Vue 3中的等效项是config.globalProperties。在实例化应用程序内的组件时,将复制这些属性:

// before - Vue 2
Vue.prototype.$http = () => {}
// after - Vue 3
const app = Vue.createApp({})
app.config.globalProperties.$http = () => {}

一个经过转换的例子如下

const app = createApp(MyApp)

app.component('button-counter', {
  data: () => ({
    count: 0
  }),
  template: '<button @click="count++">Clicked {{ count }} times.</button>'
})

app.directive('focus', {
  mounted: el => el.focus()
})

// button-counter 组件与 focus指令 不会污染全局 只在当前实例
app.mount('#app')

Provide / Inject

// 在父级
app.provide('guide', 'Vue 3 Guide')

// 在任意层次的子级
export default {
  inject: {
    book: {
      from: 'guide'
    }
  },
  template: `<div>{{ book }}</div>`
}

Tree-shaking

因为内部都重写了,所以组件内部也完全是支持摇树优化的,带来的后果就是一些方法需要显式导入来使用

import { nextTick } from 'vue'

nextTick(() => {
  // something DOM-related
})
//before
import { shallowMount } from '@vue/test-utils'
import { MyComponent } from './MyComponent.vue'

test('an async feature', async () => {
    const wrapper = shallowMount(MyComponent)

    // execute some DOM-related tasks

    await wrapper.vm.$nextTick()

    // run your assertions
})
//after
import { shallowMount } from '@vue/test-utils'
import { MyComponent } from './MyComponent.vue'
import { nextTick } from 'vue'

test('an async feature', async () => {
    const wrapper = shallowMount(MyComponent)

    // execute some DOM-related tasks

    await nextTick()

    // run your assertions
})

####受影响的API

2.x全局API 3.x用法
Vue.nextTick 拆分
Vue.observable 替换为 Vue.reactive
Vue.version 拆分
Vue.compile 仅完整版本
Vue.set 仅在兼容版本中
Vue.delete 仅在兼容版本中

参考链接

$attrs的变化

在vue2中,classstyle会被直接设置到组件的根元素并且不会出现在 $attrs中, 当inheritAttrs:false的时候

<template>
  <label>
    <input type="text" v-bind="$attrs" />
  </label>
</template>
<script>
export default {
  inheritAttrs: false
}
</script>

当这样使用的时候

<my-component id="my-id" class="my-class"></my-component>

vue2将生成以下html

<label class="my-class">
    <input type="text" id="my-id" />
</label>

vue3中$attr包含所有属性包括class与style vue3将生成以下html

<label>
    <input type="text" id="my-id" class="my-class" />
</label>

$listeners 在vue3也被移除,现在是$attrs的一部分

自定义指令的生命周期变化

简要总结:

  • API 已重命名,以便更好地与组件生命周期保持一致
  • 自定义指令将由子组件通过 v-bind="$attrs"

对比

2.x 3.x
bind beforeMount
inserted mounted
beforeUpdate
update 已经移除 改用 updated
componentUpdated updated
beforeUnmount
unbind unmounted

###生命周期变化 TODO

###scopedSlots正式弃用 v-slot 指令自 Vue 2.6.0 起被引入,提供更好的支持 slot 和 slot-scope attribute 的 API 替代方案。 v-slot 完整的由来参见这份 RFC 。 在接下来所有的 2.x 版本中 slot slot-scopeattribute 仍会被支持, 但不会出现在 Vue 3 中。 结合具名插槽要这样写

<span>
  <slot v-bind:user="user">
    {{ user.lastName }}
  </slot>
</span>

异步组件需要显式定义

Mixin合并行为变更

当来自组件的 data() 及其 mixin 或 extends 基类被合并时,现在将浅层次执行合并:

const Mixin = {
  data() {
    return {
      user: {
        name: 'Jack',
        id: 1
      }
    }
  }
}
const CompA = {
  mixins: [Mixin],
  data() {
    return {
      user: {
        id: 2
      }
    }
  }
}

vue2中结果是

{
  user: {
    id: 2,
    name: 'Jack'
  }
}

vue3中结果是

{
  user: {
    id: 2
  }
}
分类
未分类

flex布局常用属性

写组件的时候常常遇到这种情况

设计给的一个设计图 头是固定高度的 底下是自适应的

一般情况下

div{
display:flex;
flex-direction: column;
height:100%;
}

header{
height:50px;
}

body{
height:100%;
}

对一些要求不高的已经可以实现了,但是当下面组件高度很高的时候,flex会进行缩放,导致实际的header高度与预期的不一致,这个时候显式的给header 加上这两个属性就可以让他不缩放了

header{
flex-grow:0;
flex-shrink:0;
height:50px;
}

顺带一提 flex:1 flex: 1; !== flex: 1 1 auto;

  • 第一个参数表示: flex-grow 定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大
  • 第二个参数表示: flex-shrink 定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小
  • 第三个参数表示: flex-basis 给上面两个属性分配多余空间之前, 计算项目是否有多余空间, 默认值为 auto, 即项目本身的大小

分类
未分类

下一阶段预告

接下来半年内要做的事情

1.重构一个v-viewer-vue3版本的

2.开源一个可配置页面的前后端版本

欢迎加群催更 交流技术 秋秋群号:768901972

分类
未分类

git设置导致的血案-jenkins 编译 vue项目

可以看到前面报错了两次,查看报错信息 报的是

其实代码里是有这个文件的

后来想了一下 这个文件的名字我改过 之前是 user.js 后来改成了 User.js

但是我是windows git 默认不区分大小写 这边打包的是在docker里打包的 区分大小写 所以导致了这个结果

为了避免这样的惨剧 请瞧上这个设置

git config core.ignorecase false

这样windows 下 git就区分大小写了

顺带一提 git 在windows下文件目录长度是260 git自身是4096

要想突破可以

git config –global core.longpaths true

但还是建议适当控制长度

如果你有ci/cd,或者前端方向的想法,欢迎加群交流 球球群:768901972

分类
未分类

typescript 给ws添加属性类型报错怎么解决?类型“WebSocket”上不存在属性xxx

其实很简单 我以我这边使用的ws库为例子 新建一个 shims.d.ts 文件

import ws from "ws";

declare module "ws" {
  export interface WebSocket extends ws {
    $id: string;
  }
}

这样就可以实现扩展了,成功的在ws 上扩展了$id属性

另外注意一点 d.ts文件不要和.ts文件一样命名 不推荐通过后缀区分文件

还有疑问可以加群讨论 秋秋群:768901972

分类
未分类

leetcode刷题记录

随缘更新,记录下自己的刷题记录

刷题要有思路的刷题,这轮刷题的目的就是熟悉题型,没事造造火箭。所以我选择的刷题思路是按照tag进行刷题。每个tag刷一个月。刷题的频率暂定是每个工作日刷一题,不论简单或难,总之要有一题,纯粹当爱好。

更新-2020-06-09

//这题是考常见的排序,冒泡,快排,插入排序等常见的排序都可以
// https://leetcode-cn.com/problems/kth-largest-element-in-an-array/submissions/
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number}
 */
var findKthLargest = function(nums, k) {
    return nums.sort(compareNumbers)[nums.length - k]
};

function compareNumbers(a, b) {
  return a - b;
}

sort 的源码实现目前有新旧两版 旧版的是根据数组的长度,内部调用的不同的算法来实现的,数组小于10的时候调用的是插入排序 数组大于10的时候 使用的是快排

具体可以看这里https://github.com/v8/v8/blob/ad82a40509c5b5b4680d4299c8f08d6c6d31af3c/src/js/array.js

新版的看这里 https://github.com/v8/v8/blob/master/third_party/v8/builtins/array-sort.tq

更新-2020-06-08

// 这题是leetcode第一题 https://leetcode-cn.com/problems/two-sum/
// 可以使用暴力穷举法进行,也可以采用HashMap,这里采用的是HashMap来实现
/**
 * @param {number[]} nums
 * @param {number} target
 * @return {number[]}
 */
var twoSum = function (nums, target) {
    let myMap = Object.create({});
    var index = 0;
    for (var value of nums) {
        if (myMap[target - value] !== undefined) {
            return [myMap[target - value], index]
        }
        myMap[value] = index;
        index += 1;
    }
};

执行用时 :60 ms, 在所有 JavaScript 提交中击败了97.56%的用户

内存消耗 :37.9 MB, 在所有 JavaScript 提交中击败了5.08%的用户