经常用的几个javascript代码片段

2014-12-27 · 14 min read

刚到公司的时候,做了几个通用 js 组件,原生 js 写的,所以积累下一些比较好的代码片段,经过几次反复使用,质量还是比较有保证的。太长时间没写博客,这里分享出来刷刷人气。文章中的代码都在gist上同步了。

简单的模板引擎#

Handlebars等模板引擎非常好用,但是比较重量级,对于组件来说显然是不合适的,这里分享个简单的模板引擎,原生 js 实现:

function templateEngine(tpl, data) {
  var reg = /\{\{(?!\}\})(.*?)\}\}/g,
    regOut = /(^( )?(if|for|else|switch|case|break|{|}))(.*)?/g,
    code = 'var r=[];\n',
    cursor = 0,
    match

  var add = function (line, js) {
    js
      ? (code += line.match(regOut) ? line + '\n' : 'r.push(' + line + ');\n')
      : (code += line !== '' ? 'r.push("' + line.replace(/"/g, '\\"') + '");\n' : '')
    return add
  }
  while ((match = reg.exec(tpl))) {
    add(tpl.slice(cursor, match.index))(match[1], true)
    cursor = match.index + match[0].length
  }
  add(tpl.substr(cursor, tpl.length - cursor))
  code += 'return r.join("");'

  return new Function(code.replace(/[\r\t\n]/g, '')).apply(data)
}

使用方法也很简单:

var tmpl =
  '<p>' +
  '<span>{{ this.name }}</span>' +
  '{{ if( this.age > 18) { }}' +
  '<span>成年</span>' +
  '{{ } else { }}' +
  '<span>未成年</span>' +
  '{{ } }}' +
  '</p>'

var data = { name: '张三', age: 17 }

var html = templateEngine(tmpl, data)

//....

js 语句和模板混合使用。

安全字符串#

上面的模板有个小问题,就是没有过滤 html 标签等“不安全字符”,下面在给一个方法,可以用来安全的输出 html 结构,是从 Handlebars 的源码中提取的,很简单实用:

function safeString(string) {
  if (!string) {
    return ''
  }
  var escape = {
    '&': '&amp;',
    '<': '&lt;',
    '>': '&gt;',
    '"': '&quot;',
    "'": '&#x27;',
    '`': '&#x60;',
  }
  var badChars = /[&<>"'`]/g

  return string.replace(badChars, function (chr) {
    return escape[chr]
  })
}

强化 window.onload 事件#

下面这个片段是在很久之前的代码中抽出来的,用来强化window.onload 事件的绑定

function windowOnload(fun) {
  var oldonload = window.onload
  if (typeof window.onload != 'function') {
    window.onload = fun
  } else {
    window.onload = function () {
      oldonload()
      fun()
    }
  }
}

使用windowOnload 函数,就可以多次绑定window.onload 事件,并且依次执行了。

–2014/12/10 更新,翻看 Evernote 的时候,又发现几个不错的代码–

实例化函数技巧#

如下声明函数,可以不使用new 关键字实例化:

function Uploader(options) {
  if (!(this instanceof Uploader)) {
    return new Uploader(options)
  }
}

使用的时候,下面两种方式是等效的:

var uploader1 = new Uploader(options)
var uploader2 = Uploader(options)

利用浏览器特性解析 URL#

来自:http://james.padolsey.com/javascript/parsing-urls-with-the-dom/

javascript 处理 URL 还是比较麻烦的,这里巧妙的利用 a 标签一些属性,实现解析 URL,上代码:

function parseURL(url) {
    var a =  document.createElement('a');
    a.href=url;.html
    return {
        source: url,
        protocol: a.protocol.replace(':',''),
        host: a.hostname,
        port: a.port,
        query: a.search,
        params: (function(){
            var ret = {},
                seg = a.search.replace(/^\?/,'').split('&'),
                len = seg.length, i = 0, s;
            for (;i<len;i++) {
                if (!seg[i]) { continue; }
                s = seg[i].split('=');
                ret[s[0]] = s[1];
            }
            return ret;
        })(),
        file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
        hash: a.hash.replace('#',''),
        path: a.pathname.replace(/^([^\/])/,'/$1'),
        relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],
        segments: a.pathname.replace(/^\//,'').split('/')
    };
}

使用方法:

var myURL = parseURL('http://abc.com:8080/dir/index.html?id=255&m=hello#top')

myURL.file // = 'index.html'
myURL.hash // = 'top'
myURL.host // = 'abc.com'
myURL.query // = '?id=255&m=hello'
myURL.params // = Object = { id: 255, m: hello }
myURL.path // = '/dir/index.html'
myURL.segments // = Array = ['dir', 'index.html']
myURL.port // = '8080'
myURL.protocol // = 'http'
myURL.source // = 'http://abc.com:8080/dir/index.html?id=255&m=hello#top'

-暂时这么多,有了再补充-