程序人生 A log of my life

js tips

原型链

js对象都有一个__proto__属性指向它的原型对象(ES6的标准语法是Object.getPrototypeOf()),原型对象也有__proto__,自然形成一个链。当访问对象属性时,js会从对象自己,然后一直顺着原型链找下去,直到找到一个包含属性的对象。__proto__的生成规则:

  • 当直接创建对象时,创建出的对象的__proto__是Object.prototype,直接创建数组时创建出的数组的__proto__是Array.prototype。
  • 当使用new a()创建对象时,创建出的对象的__proto__是a.prototype。
  • 当使用Object.create(a)创建对象时,创建出的对象的__proto__就是a。

js执行方法时也顺着原型链去找,需要注意,即使找到了原型里的方法,this还是”子”对象,举例:

var o = {
  a: 2,
  m: function() {
    return this.a + 1;
  }
};
console.log(o.m()); // 3
var p = Object.create(o);
p.a = 4; 
console.log(p.m()); // 5

promise

lodash

虽然lodash很好用,类似Java里的Apache common,但注意lodash会给js增加30k(gzip之后)。

yarn 和 npm

在npm5之前,新项推荐使用yarn代替npm,最大的好处是对小版本的锁定,性能也好一些。

  • yarn upgrade package 可以单独升级一个包,即使这个包使用github仓库也可以(否则yarn.lock会记录commit hash,导致不升级)
  • yarn import可以按照现有node_modules目录内容生成一个yarn.lock文件,方便从npm迁移到yarn

npm5版本引入了package-lock.json,使得yarn和npm的区别已经不大了。

arrow function

和普通function的一个巨大的差异是this,arrow function保留了this为定义时刻的this,所以在vue的组件method定义中基本上不能使用arrow function

ESLint

如果代码中引用全局变量被ESLint报错,比如Media,可以在相应文件开头上加下面的注释来临时禁止报错。

/* global Media */

VSCode

VSCode如果按照ESLint插件,可以设置以下参数以打开vue文件支持和autoFix

"eslint.validate": [
    "javascript",
    {
      "language": "vue", 
      "autoFix": true 
    },
    "javascriptreact"
],
"eslint.autoFixOnSave": true,
"eslint.packageManager": "yarn",
"vetur.validation.template": false

上面最后一句是让vscode忽略一些<template>上的错误。

如果不想在search的时候包括一些文件,可以在设置中加入exclude,比如:

"search.exclude": {
    "**/node_modules": true,
    "**/bower_components": true,
    "**/build":true,
    "**/dist":true
  }

ES6 import/export

在ES6之前,JS的模块化有两种方式 AMD和CommonJS,ES6终于有了语言级别的模块化支持:

命名方式:

//------ lib.js ------
export const sqrt = Math.sqrt;
export function square(x) {
    return x * x;
}
export function diag(x, y) {
    return sqrt(square(x) + square(y));
}

//------ main.js ------
import { square, diag } from 'lib';
console.log(square(11)); // 121
console.log(diag(4, 3)); // 5
或者
import * as lib from 'lib';
console.log(lib.square(11)); // 121
console.log(lib.diag(4, 3)); // 5

default方式:

//------ myFunc.js ------
export default function () { ... };

//------ main1.js ------
import myFunc from 'myFunc';
myFunc();

混合方式:

//------ underscore.js ------
export default function (obj) {
    ...
};
export function each(obj, iterator, context) {
    ...
}
export { each as forEach };

//------ main.js ------
import _, { each } from 'underscore';

和非ES6代码的对应关系

export { Tiger }        <=> module.exports.Tiger = Tiger
module.exports = Tiger  <=> export default Tiger

现代一些js库,比如vue,会在dist里直接生成一个.esm.js文件,表示纯ES6模块文件

webpack

  • import @ 这是webpack的一个alias,用来代替src目录
  • webpack可以load json,所以可以这样import { version } from '../package.json'来导入项目package.json里的版本号。
  • webpack和rollup的对比,可以看这个小代码 https://gist.github.com/Rich-Harris/79a02519fb00837e8d5a4b24355881c0

vue

vue的目录结构建议(使用vue-router和vuex):

app/
    modelA/
        components/
            xxx.vue
        vuex/
            xxx.js
            index.js
            mutations.js
        index.js
        routes.js
    App.vue
    index.js
    routes.js
    vuex.js
assets/
router/index.js
vuex/index.js
components/     (共享的模块)
main.js
index.html

export大多通过index.js方式,写法是这样:

export { default as AAA } from './AAA';
export { default as BBB } from './BBB';

这样的好处是在import时可以比较简洁,参考这里