<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title><![CDATA[Mindspop's Blog]]></title>
  <subtitle><![CDATA[a blog recording something in mind]]></subtitle>
  <link href="/atom.xml" rel="self"/>
  <link href="mindspop.github.io/"/>
  <updated>2015-05-01T07:48:40.000Z</updated>
  <id>mindspop.github.io/</id>
  
  <author>
    <name><![CDATA[Mindspop]]></name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title><![CDATA[模块化开发之打包工具 Webpack 介绍]]></title>
    <link href="mindspop.github.io/2015/04/30/intro-of-modular-development-by-webpack/"/>
    <id>mindspop.github.io/2015/04/30/intro-of-modular-development-by-webpack/</id>
    <published>2015-04-30T14:58:56.000Z</published>
    <updated>2015-05-01T07:48:40.000Z</updated>
    <content type="html"><![CDATA[<h1 id="1-_背景介绍">1. 背景介绍</h1><h2 id="前端开发的变化">前端开发的变化</h2><p>随着 Node.js 的兴起，越来越多的人使用 JavaScript 开发后台的一些应用。同时促进了<code>模块化开发</code>和<code>包管理</code>生态系统的发展。所以目前在国外，越来越多的人使用 CommonJS 规范来处理模块加载。但是为了能让代码在浏览器上能正常运行，我们需要在上线前，将相互依赖的模块整合打包到一个文件，这样就可以避免 CommonJS 同步加载的缺陷。</p>
<h2 id="Browserify_的热捧">Browserify 的热捧</h2><p>最初在寻找打包工具时，发现大家都选择了 Browserify 这款打包工具。所以一开始我也毫不犹豫地选择了它。后来在使用过程中发现，Browserify 只能将所有文件打包成一个文件，如果需要分开打包，需要手动配置。那这样的打包方式，只适用如下一些场景：</p>
<ul>
<li>小规模网站，即代码量小</li>
<li>很少更新网站，意味着业务代码很少更新</li>
<li>不太关心第一次页面加载时长</li>
</ul>
<p>这显然不太适应大部分网站的使用场景。</p>
<h1 id="2-_从_Browserify_叛逃到_Webpack">2. 从 Browserify 叛逃到 Webpack</h1><a id="more"></a>
<p>在实际使用过程中，我考虑到了一些代码合并优化的问题，比如是否可以将一些第三方库单独打包？不需要将所有代码打包到一个文件夹。是否可以分页面打包相关的代码？这些问题 Browserify 都不予理睬。后来又通过一些博文了解到 Webpack 这款打包工具。<br>在查阅官方文档和前人研究成果后，才发现 Webpack 是一款很强大的打包工具。它除了能能解决上面提到的几个问题，同时还支持其它一些特色功能。下面我来一一介绍一下这些功能：</p>
<h2 id="Code_Splitting">Code Splitting</h2><ol>
<li>打包时排出某个文件<ul>
<li>当第三方库占整个打包文件的大小比例比较大，比如 20% 以上「When your vendors reaches a certain percentage of your total app bundle. Like 20% and up」</li>
<li>经常会更新网站「You will do quite a few updates to your application」</li>
<li>不太关心第一次页面加载时长，但是当你更新网站时，你关心优化回访用户的使用体验「You are not too concerned about perceived initial loading time, but you do have returning users and care about optimizing the experience when you do updates to the application」</li>
<li>用户是通过手机访问的「Users are on mobile」</li>
</ul>
</li>
<li>分多个入口打包文件，并提取多个合并文件中的共同文件<ul>
<li>网站有多个独立的体验部分，但是它们共享大部分代码「You have an application with multiple isolated user experiences, but they share a lot of code」</li>
<li>有一个使用较少组件的移动版本「You have a mobile version using less components」</li>
<li>是一个典型的用户前台和后台应用网站，你不想在普通用户访问时加载后台的代码「You have a typical user/admin application where you do not want to load all the admin code for a normal user」</li>
</ul>
</li>
<li>在某个文件中设置异步加载某些模块<ul>
<li>网站规模很大，用户可以访问不同的部分「You have a relatively big application where users can visit different parts of it」</li>
<li>很在意第一次页面渲染时间「You do care a lot about initial render time」</li>
</ul>
</li>
</ol>
<p>以上这些功能覆盖了大部分的使用场景。</p>
<h2 id="静态资源模块化加载">静态资源模块化加载</h2><p>我们可以把一些静态资源「Img、CSS、Font、HTML Template 等」组合打包到一个文件，实现组件化开发。</p>
<h2 id="编译文件">编译文件</h2><p>目前我们习惯用 SCSS 或 LESS 来写 CSS，用 CoffeeScript 写 JavaScript，还有 React 的 JSX 语法。<br>Webpack 提供了 sass-loader，coffee-loader, jsx-loader 等插件，当加载这些格式的模块文件时，会先执行编译，最后把编译结果引入指定文件。</p>
<h2 id="插件">插件</h2><p>Webpack 提供了很多插件，比如 UglifyJsPlugin，用来压缩 JS。更多插件可以看<a href="http://webpack.github.io/docs/list-of-plugins.html" target="_blank" rel="external">这里</a></p>
<h2 id="Sever_服务并提供类似_Liveload_功能">Sever 服务并提供类似 Liveload 功能</h2><p>Webpack 能开启一个本地 Sever，同时监听各打包文件，当某个文件发生变动时，会重新打包。同时利用它提供的 Hot Mode 功能，能实现类似 Liveload 效果，具体表现如下：</p>
<ul>
<li>CSS 变化时，<code>不用刷新页面</code>就能更新内容</li>
<li>JSX Component 变化时，不用刷新页面就能更新内容</li>
<li>某个 JS 文件变动时，会自动重新打包并刷新页面</li>
</ul>
<h1 id="3-_结语">3. 结语</h1><p>除了这些，Webpack 还提供了一些高级的功能。具体可以查看它的<a href="http://webpack.github.io/docs/" target="_blank" rel="external">官网文档</a>。但是目前来说，Webpack 不是 Gulp 的替代品，它们俩可以互相配合，发挥你的想象力，来提高前端开发的效率吧。</p>
<p>参考资料：</p>
<ol>
<li><a href="http://webpack.github.io/docs/" target="_blank" rel="external">Webpack doc</a></li>
<li><a href="http://christianalfoni.github.io/react-webpack-cookbook/Requiring-files.html" target="_blank" rel="external">React-webpack-cookbook</a></li>
<li><a href="https://github.com/petehunt/webpack-howto" target="_blank" rel="external">Webpack-how-to</a></li>
<li><a href="http://segmentfault.com/a/1190000002551952" target="_blank" rel="external">Webpack 入门指迷</a></li>
</ol>
]]></content>
    <summary type="html">
    <![CDATA[<h1 id="1-_背景介绍">1. 背景介绍</h1><h2 id="前端开发的变化">前端开发的变化</h2><p>随着 Node.js 的兴起，越来越多的人使用 JavaScript 开发后台的一些应用。同时促进了<code>模块化开发</code>和<code>包管理</code>生态系统的发展。所以目前在国外，越来越多的人使用 CommonJS 规范来处理模块加载。但是为了能让代码在浏览器上能正常运行，我们需要在上线前，将相互依赖的模块整合打包到一个文件，这样就可以避免 CommonJS 同步加载的缺陷。</p>
<h2 id="Browserify_的热捧">Browserify 的热捧</h2><p>最初在寻找打包工具时，发现大家都选择了 Browserify 这款打包工具。所以一开始我也毫不犹豫地选择了它。后来在使用过程中发现，Browserify 只能将所有文件打包成一个文件，如果需要分开打包，需要手动配置。那这样的打包方式，只适用如下一些场景：</p>
<ul>
<li>小规模网站，即代码量小</li>
<li>很少更新网站，意味着业务代码很少更新</li>
<li>不太关心第一次页面加载时长</li>
</ul>
<p>这显然不太适应大部分网站的使用场景。</p>
<h1 id="2-_从_Browserify_叛逃到_Webpack">2. 从 Browserify 叛逃到 Webpack</h1>]]>
    
    </summary>
    
      <category term="modular development" scheme="mindspop.github.io/tags/modular-development/"/>
    
      <category term="webpack" scheme="mindspop.github.io/tags/webpack/"/>
    
      <category term="Development Management" scheme="mindspop.github.io/categories/Development-Management/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[基于 Backbone.js 改造的 TodoMVC 介绍]]></title>
    <link href="mindspop.github.io/2015/04/30/%E5%9F%BA%E4%BA%8EBackbone%E6%94%B9%E9%80%A0%E7%9A%84TodoMVC%E4%BB%8B%E7%BB%8D/"/>
    <id>mindspop.github.io/2015/04/30/基于Backbone改造的TodoMVC介绍/</id>
    <published>2015-04-29T16:00:00.000Z</published>
    <updated>2015-04-30T14:56:47.000Z</updated>
    <content type="html"><![CDATA[<blockquote>
<p>前提说明：本篇是在学习<code>Backbone</code>的时候，实战练习写了一个 TodoMVC，并在原有代码上基础做了部分改进工作。</p>
</blockquote>
<h2 id="主要的改进">主要的改进</h2><ul>
<li>引入模块开发并使用<code>CommonJS</code>规范</li>
<li>使用<code>Webpack</code>工具加载和打包模块</li>
<li>将 HTML 模板独立成单一模块文件，同时让模块 JS 文件加载对应的 HTML 模板文件</li>
<li>细化了<code>View</code>层的颗粒度，将 View 拆解成：AppView、FooterView、TodoView、TodoListView</li>
<li>优化了 View 中<code>render</code>方法监听的事件类型，防止当<code>Model</code>或<code>Collection</code>发生一次变化时，View 多次重复渲染。「原例子中简单监听了<code>all</code>事件」<a id="more"></a>
<img src="/2015/04/30/基于Backbone改造的TodoMVC介绍/todomvc_structure.png">
</li>
</ul>
<h2 id="TodoMVC_架构分析">TodoMVC 架构分析</h2><h3 id="数据层">数据层</h3><ol>
<li>Todo <code>Model</code><ul>
<li>存储每一个 Todo Item 的<code>标题</code>和<code>是否完成状态</code></li>
<li>有一个业务逻辑方法：改变<code>是否完成状态</code></li>
</ul>
</li>
<li>Todos <code>Collection</code><ul>
<li>是一组 Todo Model 的集合</li>
<li>负责 Todo 列表的排序</li>
<li>负责过滤 Todo 列表中的数据「过滤剩余和完成的 Todo Item」 </li>
</ul>
</li>
</ol>
<h3 id="View_层">View 层</h3><p>尽可能最小粒度地划分 View，即保证每个独立的 View 对应一个 Model 或 Collection。复杂的 View 由简单的 View 组合而成。这样可以提高开发灵活性，也有利于后期维度。<br>这种细分 View 的方式可以理解为：</p>
<pre><code>1. <span class="keyword">view</span>-a1 + <span class="keyword">view</span>-a2 = <span class="keyword">view</span>-a
2. <span class="keyword">view</span>-b1 + <span class="keyword">view</span>-b2 + <span class="keyword">view</span>-b3 + <span class="keyword">view</span>-b4 = <span class="keyword">view</span>-b
3. <span class="keyword">view</span>-a + <span class="keyword">view</span>-b + <span class="keyword">view</span>-c = <span class="keyword">view</span>-<span class="literal">d</span>
</code></pre><p>这种划分的规则:</p>
<blockquote>
<ul>
<li>每一个最小单位的 View 都只负责处理自身的内容</li>
<li>由其它子 View 组合而成的 View 则负责统筹更小单位的 View「通常父层级的 View 负责创建、显示、隐藏或删除子级别 View」<ul>
<li>View 与 View 之间的通信，则依靠 Model 或 Collection 这个中间体「比如用户操作某个 View1 而影响另外一个 View2，代码实现上是通过修改 View2 对应的数据层来间接刷新 View2」</li>
</ul>
</li>
</ul>
</blockquote>
<h4 id="本次_TodoMVC_中对_View_的细分处理如下：">本次 TodoMVC 中对 View 的细分处理如下：</h4><ol>
<li><p>AppView</p>
<ul>
<li><p>负责组合所有 APP 内的子 View「判断是否需要增加、显示或隐藏某个组件 View」</p>
<pre><code>initialize: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{

    <span class="comment">// 新建 footer 视图</span>
    app.footerView = <span class="keyword">new</span> FooterView({
        collection: app.todos
    });

    <span class="comment">// 新建 todolist 视图</span>
    app.todoListView = <span class="keyword">new</span> TodoListView({
        collection: app.todos
    });
},

render           : <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">this</span>.renderMain();
    <span class="keyword">this</span>.renderFooter();
},

<span class="comment">//渲染 main 部分视图</span>
renderMain       : <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">if</span> (app.todos.length) {
        <span class="keyword">this</span>.$list.append(app.todoListView.el);
        <span class="keyword">this</span>.$main.show();

        <span class="comment">// 设置批量操作按钮显示状态</span>
        <span class="keyword">this</span>.toggleCheck();
    } <span class="keyword">else</span> {
        <span class="keyword">this</span>.$main.hide();
    }
},

<span class="comment">// 渲染 footer 部分视图</span>
renderFooter     : <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">if</span> (app.todos.length) {
        <span class="keyword">this</span>.$footer.append(app.footerView.el);
        <span class="keyword">this</span>.$footer.show();
    } <span class="keyword">else</span> {
        <span class="keyword">this</span>.$footer.hide();
    }
},
</code></pre></li>
</ul>
</li>
<li>TodoView<ul>
<li>负责每一个 Todo Item 的 View</li>
</ul>
</li>
<li>TodoListView<ul>
<li>负责一组 Todo Items 的 View</li>
</ul>
</li>
<li>FooterView<ul>
<li>负责 Footer 部分的 View</li>
</ul>
</li>
</ol>
<h3 id="关联数据层和_View_层">关联数据层和 View 层</h3><ol>
<li><p>TodoView + Todo Model</p>
<ul>
<li><p>将 TodoView 的方法绑定到对应 Todo Model 的事件中</p>
<pre><code>initialize: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">this</span>.listenTo(<span class="keyword">this</span>.model, {
        <span class="string">'change'</span> : <span class="keyword">this</span>.render,
        <span class="string">'destroy'</span>: <span class="keyword">this</span>.remove,
        <span class="string">'visible'</span>: <span class="keyword">this</span>.toggleVisible
    });

    <span class="keyword">this</span>.render();
},
</code></pre></li>
<li><p>利用 Todo Model 的数据渲染 TodoView 的模板</p>
<pre><code><span class="keyword">var</span> itemTpl = require('../../<span class="keyword">template</span>/item-tpl.ejs');
<span class="keyword">var</span> <span class="type">TodoView</span> = <span class="type">Backbone</span>.<span class="type">View</span>.extend({
    <span class="keyword">template</span>: itemTpl,
    render       : function () {
        ...

        <span class="keyword">var</span> tmpl = this.<span class="keyword">template</span>(this.model.toJSON());
        this.$el.html(tmpl);

        ...
        <span class="keyword">return</span> this;
    },
    ...
)};
</code></pre></li>
<li><p>Todo View 中一些方法可以修改 Model 数据</p>
<pre><code><span class="comment">// 改变 Model complete 状态</span>
toggleCompleted: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">this</span>.model.toggleCompleted();
},

<span class="comment">// 清除 Model</span>
clear         : <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">this</span>.model.destroy();
},
</code></pre></li>
</ul>
</li>
<li><p>TodoListView + Todos Collection</p>
<ul>
<li><p>将 TodoListView 的方法绑定到对应 Todos Collection 的事件中</p>
<pre><code>initialize: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">this</span>.listenTo(<span class="keyword">this</span>.collection, {
        <span class="string">'add'</span>             : <span class="keyword">this</span>.addOne,
        <span class="string">'reset'</span>           : <span class="keyword">this</span>.addAll,
        <span class="string">'change:completed'</span>: <span class="keyword">this</span>.filterOne,
        <span class="string">'filter'</span>          : <span class="keyword">this</span>.filterAll,
        <span class="string">'destroy'</span>         : <span class="keyword">this</span>.render
    });
},
</code></pre></li>
<li><p>TodoListView 可以访问 Todos Collection, 从而间接访问其中的 Model</p>
<pre><code>filterOne : <span class="function"><span class="keyword">function</span> <span class="params">(todo)</span> </span>{
    todo.trigger(<span class="string">'visible'</span>);
},
filterAll : <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">this</span>.collection.<span class="keyword">each</span>(<span class="keyword">this</span>.filterOne, <span class="keyword">this</span>);
}
</code></pre></li>
</ul>
</li>
<li><p>FooterView + Todos Collection</p>
<ul>
<li><p>将 FooterView 的方法绑定到对应 Todos Collection 的事件中</p>
<pre><code>initialize: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    <span class="keyword">this</span>.listenTo(<span class="keyword">this</span>.collection, <span class="string">'add remove reset change:completed'</span>, <span class="keyword">this</span>.render);
    <span class="keyword">this</span>.listenTo(<span class="keyword">this</span>.collection, <span class="string">'filter'</span>, <span class="keyword">this</span>.setSelectedTab);
},
</code></pre></li>
<li><p>FooterView 可以访问 Todos Collection</p>
<pre><code><span class="comment">// 清除已经完成的 todoitem</span>
clearCompleted: <span class="function"><span class="keyword">function</span> <span class="params">()</span> </span>{
    _.invoke(<span class="keyword">this</span>.collection.completed(), <span class="string">'destroy'</span>);
}
</code></pre></li>
<li><p>利用 Todos Collection 的数据渲染 FooterView</p>
<pre><code><span class="keyword">var</span> footerTpl = require('../../<span class="keyword">template</span>/footer-tpl.ejs');

<span class="keyword">var</span> <span class="type">FooterView</span> = <span class="type">Backbone</span>.<span class="type">View</span>.extend({
    <span class="keyword">template</span>: footerTpl,
    ...
    render        : function () {

        // 提取当前所绑定的 collection 数据的状态
        <span class="keyword">var</span> remaining = this.collection.where({
            completed: <span class="literal">false</span>
        }).length;
        <span class="keyword">var</span> completed = this.collection.where({
            completed: <span class="literal">true</span>
        }).length;

        // 利用获取的 collection 数据渲染模板
        <span class="keyword">var</span> footerView = this.<span class="keyword">template</span>({
            remaining: remaining,
            completed: completed
        });

        this.$el.html(footerView);

        ...
    },
    ...
});    
</code></pre></li>
</ul>
</li>
</ol>
]]></content>
    <summary type="html">
    <![CDATA[<blockquote>
<p>前提说明：本篇是在学习<code>Backbone</code>的时候，实战练习写了一个 TodoMVC，并在原有代码上基础做了部分改进工作。</p>
</blockquote>
<h2 id="主要的改进">主要的改进</h2><ul>
<li>引入模块开发并使用<code>CommonJS</code>规范</li>
<li>使用<code>Webpack</code>工具加载和打包模块</li>
<li>将 HTML 模板独立成单一模块文件，同时让模块 JS 文件加载对应的 HTML 模板文件</li>
<li>细化了<code>View</code>层的颗粒度，将 View 拆解成：AppView、FooterView、TodoView、TodoListView</li>
<li>优化了 View 中<code>render</code>方法监听的事件类型，防止当<code>Model</code>或<code>Collection</code>发生一次变化时，View 多次重复渲染。「原例子中简单监听了<code>all</code>事件」]]>
    
    </summary>
    
      <category term="Backbone" scheme="mindspop.github.io/tags/Backbone/"/>
    
      <category term="JavaScript" scheme="mindspop.github.io/tags/JavaScript/"/>
    
      <category term="MVC" scheme="mindspop.github.io/tags/MVC/"/>
    
      <category term="JavaScript Tech" scheme="mindspop.github.io/categories/JavaScript-Tech/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[JavaScript Style Guide]]></title>
    <link href="mindspop.github.io/2015/04/12/javascript-style-guide/"/>
    <id>mindspop.github.io/2015/04/12/javascript-style-guide/</id>
    <published>2015-04-11T16:00:00.000Z</published>
    <updated>2015-04-30T14:56:47.000Z</updated>
    <content type="html"><![CDATA[<blockquote>
<p>前提说明：<br>本文通过对比一些主流 JavaScript Style Guide, 摘录了一些值得借鉴的语法书写方式，以提高程序执行性能。而格式问题「Formatting: space, newline, etc」暂且被忽略了，因为一般可以通过 IDE 编辑器设置处理，写的时候可以按照自己的习惯来，通过编辑器格式配置方式以保持和团队风格统一，常见格式建议可查看<a href="#reference">参考资料</a>。</p>
</blockquote>
<a id="more"></a>
<h2 id="变量声明「Variable_Declaration」">变量声明「Variable Declaration」</h2><h3 id="Object">Object</h3><ul>
<li><p>使用 Literal declaration</p>
<pre><code><span class="variable"><span class="keyword">var</span> item</span> = {};
</code></pre></li>
<li><p>使用同义词替换保留字</p>
<pre><code><span class="comment">// bad</span>
<span class="keyword">var</span> superman = {
  <span class="class"><span class="keyword">class</span>:</span> <span class="symbol">'alie</span>n'
};

<span class="comment">// bad</span>
<span class="keyword">var</span> superman = {
  klass: <span class="symbol">'alie</span>n'
};

<span class="comment">// good</span>
<span class="keyword">var</span> superman = {
  <span class="class"><span class="keyword">type</span>:</span> <span class="symbol">'alie</span>n'
};
</code></pre></li>
</ul>
<h3 id="Array">Array</h3><pre><code><span class="variable"><span class="keyword">var</span> items</span> = [];
</code></pre><h3 id="Function">Function</h3><ul>
<li><p>如果在<code>non-function block</code>(if, while, etc)，声明一个函数，需要把函数赋值给一个变量。「ECMA-262 中定义<code>a list of statements</code>为<code>a block</code>」</p>
<pre><code><span class="comment">// bad</span>
<span class="keyword">if</span> (currentUser) {
    <span class="function"><span class="keyword">function</span> <span class="title">test</span><span class="params">()</span> </span>{
    <span class="built_in">console</span>.log(<span class="string">'Nope.'</span>);
    }
}

<span class="comment">// good</span>
<span class="keyword">var</span> test;
<span class="keyword">if</span> (currentUser) {
  test = <span class="function"><span class="keyword">function</span> <span class="title">test</span><span class="params">()</span> </span>{
    <span class="built_in">console</span>.log(<span class="string">'Yup.'</span>);
  };
}
</code></pre></li>
<li>函数参数中不要使用<code>arguments</code>保留字「因为会覆盖 function scope 中的 arguments」</li>
</ul>
<h3 id="关于声明提升「Hoisting」">关于声明提升「Hoisting」</h3><ul>
<li>变量声明会被提前，但是赋值不会</li>
<li><p>函数声明时，函数名和函数体都会被提前</p>
<pre><code><span class="function"><span class="keyword">function</span> <span class="title">example</span><span class="params">()</span> </span>{

    <span class="comment">// =&gt; Flying</span>
      superPower(); 

      <span class="function"><span class="keyword">function</span> <span class="title">superPower</span><span class="params">()</span> </span>{
        <span class="built_in">console</span>.log(<span class="string">'Flying'</span>);
      }
}
</code></pre></li>
</ul>
<h2 id="类型检查「Type_Checking_」">类型检查「Type Checking 」</h2><h3 id="实际类型检测「Actual_Types_Checking」">实际类型检测「Actual Types Checking」</h3><h4 id="Types:_String、Number、Boolean、Object_类型检查">Types: String、Number、Boolean、Object 类型检查</h4><pre><code><span class="comment">// 其实 typeof 返回值一定是一个字符串，这里没必要使用 ===，即使用 == 即可</span>
<span class="keyword">typeof</span> variable == <span class="string">"Types"</span>
</code></pre><h4 id="Array-1">Array</h4><pre><code>Array.<span class="function"><span class="title">isArray</span><span class="params">(arrayLikeObject)</span></span>
</code></pre><h4 id="Node">Node</h4><pre><code><span class="comment">// nodeType 返回值一定是 number，这里没必要使用 ===，即使用 == 即可</span>
elem<span class="class">.nodeType</span> == <span class="number">1</span>
</code></pre><h4 id="null">null</h4><pre><code><span class="regexp">//</span> 注意：<span class="keyword">typeof</span> <span class="literal">null</span> 返回的是 “object”
variable === <span class="literal">null</span>
</code></pre><h4 id="undefined">undefined</h4><pre><code><span class="comment">// 1. Global Variable</span>
<span class="comment">// 这里 typeof 返回值也肯定是字符串，所以用 == 即可</span>
<span class="keyword">typeof</span> variable == <span class="string">"undefined"</span>

<span class="comment">// 2. Local Variable</span>
variable === <span class="literal">undefined</span>
</code></pre><h4 id="null_or_undefined">null or undefined</h4><pre><code><span class="comment">// undefined 值可能被重写</span>
<span class="built_in">variable</span> <span class="subst">==</span> <span class="built_in">null</span>
</code></pre><h3 id="类型强制转换「Coerced_Types」">类型强制转换「Coerced Types」</h3><blockquote>
<p>类型转换部分语法原理，可参考这篇文章：<a href="https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108" target="_blank" rel="external">Truth, Equality and JavaScript</a></p>
</blockquote>
<pre><code><span class="keyword">var</span> number = <span class="number">1</span>,
 <span class="keyword">string</span> = <span class="string">"1"</span>,
 <span class="keyword">bool</span> = <span class="keyword">false</span>;

 <span class="comment">// "1"</span>
 number + <span class="string">""</span>;

 <span class="comment">// 1</span>
 +<span class="keyword">string</span>;    

 <span class="comment">// 0</span>
 +<span class="keyword">bool</span>; 

 <span class="comment">// "false"</span>
 <span class="keyword">bool</span> + <span class="string">""</span>;

 <span class="comment">// "false"     </span>
 !<span class="keyword">string</span>;

 <span class="comment">// "true"</span>
 !!number;
</code></pre><h2 id="条件判断「Conditional_Evaluation」">条件判断「Conditional Evaluation」</h2><h3 id="Booleans,_Truthies_&amp;_Falsies_判断">Booleans, Truthies &amp; Falsies 判断</h3><pre><code><span class="comment">// Booleans:</span>
<span class="literal">true</span>, <span class="literal">false</span>

<span class="comment">// Truthy:</span>
<span class="string">"foo"</span>, <span class="number">1</span>, <span class="built_in">Object</span>

<span class="comment">// Falsy:</span>
<span class="string">""</span>, <span class="number">0</span>, <span class="literal">null</span>, <span class="literal">undefined</span>, <span class="literal">NaN</span>, <span class="keyword">void</span> <span class="number">0</span>
</code></pre><h3 id="判断数组是否为空">判断数组是否为空</h3><pre><code><span class="comment">// 当数组不为空时</span>
<span class="keyword">if</span> (<span class="built_in">array</span><span class="built_in">.</span>length) <span class="attribute">...</span>

<span class="comment">// 当数组为空时</span>
<span class="keyword">if</span> (<span class="subst">!</span><span class="built_in">array</span><span class="built_in">.</span>length) <span class="attribute">...</span>
</code></pre><h3 id="判断字符串是否为空">判断字符串是否为空</h3><pre><code><span class="comment">// 当字符串不为空时</span>
<span class="keyword">if</span> (<span class="built_in">string</span>) <span class="attribute">...</span>

<span class="comment">// 当字符串为空时</span>
<span class="keyword">if</span> (<span class="subst">!</span><span class="built_in">string</span>) <span class="attribute">...</span>
</code></pre><h3 id="判断引用是否为空「evaluating_a_reference」">判断引用是否为空「evaluating a reference」</h3><pre><code><span class="regexp">//</span> 当引用不为空时
<span class="keyword">if</span> (foo) ...

<span class="regexp">//</span> 当引用为空时
<span class="keyword">if</span> (!foo) ...

<span class="regexp">//</span> 除去匹配: <span class="number">0</span>, <span class="string">""</span>, <span class="literal">null</span>, <span class="literal">undefined</span>, NaN 情况，只匹配 boolean <span class="literal">false</span>
<span class="keyword">if</span> (foo === <span class="literal">false</span>) ...

<span class="regexp">//</span> 只匹配 <span class="literal">null</span> <span class="keyword">or</span> <span class="literal">undefined</span>, 因为 <span class="literal">null</span> == <span class="literal">undefined</span>
<span class="keyword">if</span> (foo == <span class="literal">null</span>) ...
</code></pre><h3 id="判断数组中是否存在某元素">判断数组中是否存在某元素</h3><pre><code>array.<span class="function"><span class="title">indexOf</span><span class="params">( <span class="string">"a"</span> )</span></span> &gt;= <span class="number">0</span>
</code></pre><h2 id="常见操作优化">常见操作优化</h2><h3 id="Array_操作">Array 操作</h3><ul>
<li>使用 Array.push 而不是直接赋值</li>
<li>使用 Array.slice 拷贝数组</li>
<li>使用 Array.prototype.slice.call(arrayLikeObject) 将 array-like 对象转换为数组</li>
</ul>
<h3 id="String_操作">String 操作</h3><ul>
<li>使用 Array.join 拼接字符串</li>
<li><p>处理长字符串跨行时，用 “+” 拼接字符串</p>
<pre><code>// bad
var errorMessage = 'This is a super long error that was thrown because of Batman. When you <span class="operator"><span class="keyword">stop</span> <span class="keyword">to</span> think about how Batman had anything <span class="keyword">to</span> <span class="keyword">do</span> <span class="keyword">with</span> this, you would <span class="keyword">get</span> nowhere <span class="keyword">fast</span>.<span class="string">';

// bad
var errorMessage = '</span>This <span class="keyword">is</span> a super long error that was thrown because \
<span class="keyword">of</span> Batman. <span class="keyword">When</span> you <span class="keyword">stop</span> <span class="keyword">to</span> think about how Batman had anything <span class="keyword">to</span> <span class="keyword">do</span> \
<span class="keyword">with</span> this, you would <span class="keyword">get</span> nowhere \
<span class="keyword">fast</span>.<span class="string">';

// good
var errorMessage = '</span>This <span class="keyword">is</span> a super long error that was thrown because <span class="string">' +
  '</span><span class="keyword">of</span> Batman. <span class="keyword">When</span> you <span class="keyword">stop</span> <span class="keyword">to</span> think about how Batman had anything <span class="keyword">to</span> <span class="keyword">do</span> <span class="string">' +
  '</span><span class="keyword">with</span> this, you would <span class="keyword">get</span> nowhere <span class="keyword">fast</span>.<span class="string">';</span></span>
</code></pre></li>
</ul>
<h3 id="Object_操作">Object 操作</h3><ul>
<li>使用<code>.</code>读取字符串属性</li>
<li>使用<code>[]</code>读取变量数量</li>
</ul>
<p><a href="id:reference" target="_blank" rel="external">参考资料</a>：</p>
<ol>
<li><a href="https://github.com/rwaldron/idiomatic.js" target="_blank" rel="external">Principles of Writing Consistent, Idiomatic JavaScript</a></li>
<li><a href="https://github.com/airbnb/javascript" target="_blank" rel="external">Airbnb JavaScript Style Guide</a></li>
<li><a href="https://javascriptweblog.wordpress.com/2011/02/07/truth-equality-and-javascript/#more-2108" target="_blank" rel="external">Truth, Equality and JavaScript</a></li>
</ol>
]]></content>
    <summary type="html">
    <![CDATA[<blockquote>
<p>前提说明：<br>本文通过对比一些主流 JavaScript Style Guide, 摘录了一些值得借鉴的语法书写方式，以提高程序执行性能。而格式问题「Formatting: space, newline, etc」暂且被忽略了，因为一般可以通过 IDE 编辑器设置处理，写的时候可以按照自己的习惯来，通过编辑器格式配置方式以保持和团队风格统一，常见格式建议可查看<a href="#reference">参考资料</a>。</p>
</blockquote>]]>
    
    </summary>
    
      <category term="JavaScript" scheme="mindspop.github.io/tags/JavaScript/"/>
    
      <category term="JavaScript Tech" scheme="mindspop.github.io/categories/JavaScript-Tech/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[元素在 Z 轴方向上的堆叠顺序规则分析]]></title>
    <link href="mindspop.github.io/2014/08/30/stacking-context-analysis-of-element-in-z-axis/"/>
    <id>mindspop.github.io/2014/08/30/stacking-context-analysis-of-element-in-z-axis/</id>
    <published>2014-08-29T16:00:00.000Z</published>
    <updated>2015-04-11T16:56:41.000Z</updated>
    <content type="html"><![CDATA[<p>在正式开始介绍前，我们先提出这样一个疑问：</p>
<blockquote>
<p>当两个元素位置互相堆叠在一起时，CSS 样式是如何决定哪个元素显示在前，哪个元素显示在后的呢？</p>
</blockquote>
<p>为了解决这个问题，在左右、上下的布局基础上，CSS 2.1 引入了第三维度<code>Z 轴</code>的概念。CSS 将所有元素都被纳入一个<code>Stacking Context</code>中，根据某种规则控制元素堆叠的优先顺序，下面主要详细介绍一下这种规则。</p>
<h2 id="Stacking_Context_介绍">Stacking Context 介绍</h2><p>CSS 2.1 Spec 对<code>Stacking Context</code>的描述：</p>
<blockquote>
<p>The order in which the rendering tree is painted onto the canvas is described in terms of stacking contexts.</p>
</blockquote>
<p>我对这句话的理解是：<code>Stacking Context</code>有着一套规范元素堆叠顺序的规则。在渲染页面时，根据这套顺序规则依次在 Z 轴上显示不同元素。</p>
<h3 id="Stacking_Context_的特性">Stacking Context 的特性</h3><ul>
<li>每个文档布局中存在多个 <code>Stacking Context</code>。而产生一个新的 <code>Stacking Context</code> 是有条件的「详见下文」</li>
<li>在每个<code>Stacking Context</code>中可以嵌套其它的<code>Stacking Context</code></li>
<li>每个<code>Stacking Context</code>中的元素位置和同级的<code>Stacking Context</code>中元素位置的顺序是互相独立的</li>
<li>每个<code>Stacking Context</code>是自包含的，即当父元素形成一个<code>Stacking Context</code>「此时作为后代元素的<code>Parent Stacking Context</code>」，所有内部后代元素的堆叠顺序都仅限在<code>Parent Stacking Context</code>比较<a id="more"></a>
<h3 id="Stacking_Context_内部元素排列顺序规则">Stacking Context 内部元素排列顺序规则</h3>按抵部-&gt;顶部顺序，可以抽象成七层布局：</li>
</ul>
<img src="/2014/08/30/stacking-context-analysis-of-element-in-z-axis/stacking-context-order.png">
<h3 id="归属于不同_Stacking_Context_的元素顺序比较">归属于不同 Stacking Context 的元素顺序比较</h3><p>上面介绍的堆叠顺序规则只用于比较同属于一个<code>Parent Stacking Context</code>的元素堆叠顺序。如果两个元素属于两个不同的<code>Parent Stacking Context</code>，那么它俩的顺序是由<code>Parent Stacking Context</code>的顺序决定的。</p>
<p>这句话说的有点绕，我们用图例来解释：</p>
<img src="/2014/08/30/stacking-context-analysis-of-element-in-z-axis/parent-stacking-context.png">
<p>从图例中可以看到，<code>DIV #2.1</code>元素位置在<code>DIV #1.1</code>和<code>DIV #1.2</code>之下，尽管它的<code>z-index</code>值为 100。产生这个现象的原因就是因为<code>DIV #2.1</code>和<code>DIV #1.1</code>不在同一个<code>Parent Stacking Context</code>。所以此时需要找到<code>DIV #2.1</code>的<code>Parent Stacking Context</code>，即为<code>DIV #2</code>，此时比较<code>DIV #2</code>和<code>DIV #1.1</code>的堆叠顺序，因为<code>DIV #2</code>的<code>z-index</code>值为 1，所以它在<code>DIV #1.1</code>元素的下方，同时<code>DIV #2.1</code>的位置顺序受限于<code>DIV #2</code>，最后的排布顺序就如图所示。</p>
<blockquote>
<p><strong>图例解释说明：</strong></p>
<ul>
<li>DIV #n，#n.n，#n.n.n 表示互为父-子元素关系，具体<code>HTML</code>结构层次：</li>
</ul>
<blockquote>
<ul>
<li>Body<ul>
<li>DIV #1<ul>
<li>DIV #1.1<ul>
<li>DIV #1.2</li>
</ul>
</li>
</ul>
</li>
<li>DIV #2<pre><code>* <span class="keyword">DIV</span> <span class="string">#2</span>.<span class="number">1</span>
  * <span class="keyword">DIV</span> <span class="string">#2</span>.<span class="number">1.1</span>
   * <span class="keyword">DIV</span> <span class="string">#2</span>.<span class="number">1.2</span>
</code></pre></li>
</ul>
</li>
</ul>
</blockquote>
<ul>
<li>绿色背景表示根元素「即<code>&lt;html&gt;</code>」产生的<code>Stacking Context</code></li>
<li>颜色相同的元素表示它们同属于一个<code>Parent Stacking Context</code>，<code>Stacking Context</code>层次关系：</li>
</ul>
<blockquote>
<ul>
<li>Root<ul>
<li>DIV #1</li>
<li>DIV #1.1</li>
<li>DIV #1.2 </li>
<li>DIV #2<ul>
<li>DIV #2.1<ul>
<li>DIV 2.1.1</li>
<li>DIV 2.1.2</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
</blockquote>
</blockquote>
<p>既然元素处于哪个<code>Parent Stacking Context</code>也会影响元素显示顺序，那么我们来看看元素的<code>Parent Stacking Context</code>是如何产生的：</p>
<blockquote>
<p>最外层的<code>Stacking Context</code>是根元素产生的，那么我们可以理解为它是所有元素的<code>Parent Stacking Context</code>。但当有新的<code>Stacking Context</code>产生时，这个新<code>Stacking Context</code>就是所有后代元素的<code>Parent Stacking Context</code>。以此类推，每当父元素产生一个新<code>Stacking Context</code>，就给后代元素提供了一个<code>Parent Stacking Context</code>。</p>
</blockquote>
<h3 id="产生新_Stacking_Context_的条件">产生新 Stacking Context 的条件</h3><ul>
<li><code>Root element</code>「可以理解为第一个<code>Stacking Context</code>，用来包含其它的<code>Stacking Context</code>」</li>
<li><code>Positioned</code>元素的<code>z-index</code>值不是<code>auto</code></li>
<li>元素的<code>Opacity</code>值小于 1「可以看作是给普通元素增加了<code>Position</code>属性，且<code>z-index</code>值为 0「详细可见 <a href="http://www.w3.org/TR/css3-color/#transparency" target="_blank" rel="external">CSS Spec 2.1</a>」</li>
<li>Chrome 22+ 和 Mobile WebKit,<code>z-index</code>值为<code>auto</code>的<code>fixed position</code>元素</li>
</ul>
<h2 id="Positioned_元素堆叠顺序规则">Positioned 元素堆叠顺序规则</h2><p>上面介绍了每一个<code>Stacking Context</code>内部元素的堆叠顺序，这里进一步详细介绍<code>Positioned</code>元素的堆叠顺序。</p>
<h3 id="z-index_的作用">z-index 的作用</h3><p><code>Positioned</code>元素的堆叠顺序是由<code>z-index</code>决定的。<code>z-index</code>有2个作用：</p>
<ol>
<li>决定<code>Positioned</code>元素的<code>Stack Level</code>「可以理解为堆叠优先级，<code>Stack Level</code>值为整数，值大的放在上层」</li>
<li>决定是否形成一个新的<code>Stacking Context</code></li>
</ol>
<h3 id="z-index_属性值">z-index 属性值</h3><p><code>z-index</code> 有两个属性值：<code>&lt;integer&gt;</code>和<code>&lt;auto&gt;</code>「注：只有<code>Positioned</code>元素的<code>Z-index</code>值才有效」。</p>
<ul>
<li><code>&lt;integer&gt;</code>：当<code>Z-index</code>设置了一个整数「负整数，零，正整数」时，<code>Positioned</code>元素就产生了一个新的<code>Stacking Context</code>，同时这个整数代表了当前元素的<code>Stack Level</code></li>
<li><code>&lt;auto&gt;</code>：该值说明当前元素的<code>Stack Level</code>值为 0。但此时并没有产生新的<code>Stacking Context</code>，除非这个元素是个根元素「注：这里可以看出<code>z-index = auto</code>和<code>z-index = 0</code>的区别」</li>
</ul>
<h2 id="总结">总结</h2><ol>
<li>任意一个元素都归属一个<code>Stacking Context</code>，<code>Stacking Context</code>可以互相嵌套，从而形成一个<code>Stacking Context</code>层级体系。「<code>Root element</code>是一个初始的<code>Stacking Context</code>，它包裹了其它的<code>Stacking Context</code>」</li>
<li>在每一个<code>Stacking Context</code>内部，有特定堆叠优先级规则决定不同类型元素的堆叠顺序「<code>Positioned</code>元素的堆叠顺序由<code>z-index</code>值决定」</li>
<li>当两个元素归属于不同的<code>Parent Stacking Context</code>时，它们的堆叠顺序互不干扰</li>
</ol>
<h3 id="参考资料">参考资料</h3><ol>
<li><a href="http://www.w3.org/TR/CSS21/zindex.html" target="_blank" rel="external">http://www.w3.org/TR/CSS21/zindex.html</a></li>
<li><a href="http://www.w3.org/TR/CSS21/visuren.html#layers" target="_blank" rel="external">http://www.w3.org/TR/CSS21/visuren.html#layers</a></li>
<li><a href="http://www.w3.org/TR/css3-color/#transparency" target="_blank" rel="external">http://www.w3.org/TR/css3-color/#transparency</a></li>
<li><a href="http://segmentfault.com/a/1190000000460664" target="_blank" rel="external">http://segmentfault.com/a/1190000000460664</a></li>
<li><a href="http://gbspacing.com/z-index.gb" target="_blank" rel="external">http://gbspacing.com/z-index.gb</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index" target="_blank" rel="external">https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index</a></li>
</ol>
]]></content>
    <summary type="html">
    <![CDATA[<p>在正式开始介绍前，我们先提出这样一个疑问：</p>
<blockquote>
<p>当两个元素位置互相堆叠在一起时，CSS 样式是如何决定哪个元素显示在前，哪个元素显示在后的呢？</p>
</blockquote>
<p>为了解决这个问题，在左右、上下的布局基础上，CSS 2.1 引入了第三维度<code>Z 轴</code>的概念。CSS 将所有元素都被纳入一个<code>Stacking Context</code>中，根据某种规则控制元素堆叠的优先顺序，下面主要详细介绍一下这种规则。</p>
<h2 id="Stacking_Context_介绍">Stacking Context 介绍</h2><p>CSS 2.1 Spec 对<code>Stacking Context</code>的描述：</p>
<blockquote>
<p>The order in which the rendering tree is painted onto the canvas is described in terms of stacking contexts.</p>
</blockquote>
<p>我对这句话的理解是：<code>Stacking Context</code>有着一套规范元素堆叠顺序的规则。在渲染页面时，根据这套顺序规则依次在 Z 轴上显示不同元素。</p>
<h3 id="Stacking_Context_的特性">Stacking Context 的特性</h3><ul>
<li>每个文档布局中存在多个 <code>Stacking Context</code>。而产生一个新的 <code>Stacking Context</code> 是有条件的「详见下文」</li>
<li>在每个<code>Stacking Context</code>中可以嵌套其它的<code>Stacking Context</code></li>
<li>每个<code>Stacking Context</code>中的元素位置和同级的<code>Stacking Context</code>中元素位置的顺序是互相独立的</li>
<li>每个<code>Stacking Context</code>是自包含的，即当父元素形成一个<code>Stacking Context</code>「此时作为后代元素的<code>Parent Stacking Context</code>」，所有内部后代元素的堆叠顺序都仅限在<code>Parent Stacking Context</code>比较]]>
    
    </summary>
    
      <category term="css" scheme="mindspop.github.io/tags/css/"/>
    
      <category term="CSS Tech" scheme="mindspop.github.io/categories/CSS-Tech/"/>
    
  </entry>
  
</feed>