Giter VIP home page Giter VIP logo

hywilliam.github.io's People

Contributors

hywilliam avatar

Stargazers

 avatar

Watchers

 avatar  avatar

hywilliam.github.io's Issues

java培训(一)

历史

编辑器

eclipse, myeclipse 7 (考试用), idea

数据

jdk源码

ArrayList 数据类型

书📚

Thinking in, 核心卷

方法调用, 静态成员变量, 静态方法
类成员变量, 实例化

实例化对象

为声明的对象分配内存空间

构造方法

析构

方法重载

实例方法和类方法

包package

package pkg1[.pkg2[.pkg3]]

类和对象的使用

public private protected default
Q: java的数据类型有哪些?
Q: 为什么分为基本类型和引用类型?
Q: 面向对象问题:权限限定符有几个?

final类,不能被继承。final方法,不能被重写。

java.lang.Object

面向对象程序设计

继承

extends, super

多态

抽象类,抽象方法

abstract, 单例模式(创建型),模板方法模式

接口

interface
#1.8 新特性

多线程写法

Thread

Vi “进阶”

使用vi也一年有余了,但是可能在日常使用中过于满足了,只是顺手了一些基本操作,虽然不影响正常的编码。但还是想再挖掘一些更加功效的使用出来。在此做一下记录:

Moving the Cursor

  • ^ 光标移到行首第一个非空字符
  • :0 || gg ||1G 光标移到首行头
  • :n || ngg || nG 光标移到第n行头
  • :$ || G 光标移到尾行头

Operate Text

  • ctrl + r 恢复撤销
  • D 删除本行光标之后的所有文本
  • ndd 删除n行
  • dw || cw 删除一个单词
  • dnw 删除n个单词

Searching Text

  • /string 查找以string开头的text
  • ?string 查找以string结尾的text
  • n 在查找到的text中跳
  • N

区块选取

  • shift + v
  • ctrl + v

VIM学习指南

URL解析 & window.location

在日常的学习工作中遇到的URL相关的问题,基本就是两个,一个是整体的解析,一个是查询字段的分离。下面来进行下前端URL的一些知识整理。

比较经典的URL解析方法:

  • 正则匹配
  • DOM引入
/**
* 正则方法:大神的正则匹配方案,看得头疼脑热。
* 传入url字符串,得到解析后的uri对象,有两种模式可供自由切换。
* 参数封装到函数的一个内置属性中。
*/
function parseUri (str) {
    var o   = parseUri.options,
        m   = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
        uri = {},
        i   = 14;

    while (i--) uri[o.key[i]] = m[i] || "";

    uri[o.q.name] = {};
    uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
        if ($1) uri[o.q.name][$1] = $2;
    });

    return uri;
};

parseUri.options = {
    strictMode: false,
    key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],
    q:   {
        name:   "queryKey",
        parser: /(?:^|&)([^&=]*)=?([^&]*)/g
    },
    parser: {
        strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
        loose:  /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
    }
};
/**
*   DOM引入方案:非常hack的一个处理,引入一个a标签,通过a标签与Location对象的隐式关联来处理。
*   实际测试,时间要慢于正则,但是其语义化便于理解。更易审查。比较nice。
*/
function parseURL(url) {
    var a =  document.createElement('a');
    a.href = url;
    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('/')
    };
}

说道URL解析,不得不提的就是Location对象了,这是浏览器环境下的一个webAPI。说白了可以理解为,你浏览器窗口中输入的dns地址。那么,它有什么功用呢?除了获取当前文档的uri地址之外,它还可以载入新的文档, 刷新当前文档。

首先,有两种方式可以取到Location对象。而且它们总是相等的。

window.location === document.location

当我们在控制台打出location对象时,会发现其属性值大多和我们上面的parseURL的返回对象很像。对,其实可以理解为location返回的对象就是一个浏览器内置实现的url解析。

正好这里通过location的使用来做一下url查询参数的分离。(其实就是parseURL方法的params属性)

/**
* 这个函数解析来自URL查询串中的name=value参数对。
* 将得到的参数对存储在一个对象中,并返回该对象。
*/
function urlArgs() {
    var args = {};
    var query = location.search.substring(1);
    var pairs = query.split('&');
    for(var i = 0; i < pairs.length; i++) {
        var pos = pairs[i].indexOf('=');
        if(pos === -1) continue;
        var name = pairs[i].substring(0, pos);
        var val = pairs[i].substring(pos+1);
        val = decodeURIComponent(val);
        args[name] = val;
    }
    return args;
}

此外,location还有三个很有用的方法,分别是assgin(), replace(), reload()

  • assgin():接收一个url地址,并使窗口载入url中的文档。
  • replace():同样载入所传url地址的文档,区别在于载入并替换当前文档,不再保留当前url的历史记录。即是说,replace后,无法通过返回按钮,回到上一页。而assgin()打开新的地址是可以返回的。
  • reload():直接调用刷新当前页。

思考

URL相关的解析处理,无外乎正则匹配和字符串操作。但是要明晰的是,URL的几大部分,以https://bob:[email protected]:8080/file;p=1?q=2#third为例,从左至右分别是:

  1. protocol---协议名:https
  2. 用户:bob
  3. 密码:bobby
  4. hostname---主机地址:www.lunatech.com
  5. port---端口号:8080
  6. pathname---文件路径:/file
  7. 文件参数:p=1
  8. search---查询参数:q=2
  9. hash---页内段:third

清晰了URL的结构,那无论是要怎么操作都能得心应手。

参考资料

阿里笔试总结,携程,七牛面经

其实之前也已经有过两次阿里内推电话面试的经历了。但是无奈当时积累有限,做不出有效的总结。相信好的总结是下一步继续进步的阶梯。

首先,总的来说,经过最近这几次,收获是颇丰的。不仅让自己知道了一些深浅,也不再像第一次电面时那么紧张了。就电话面试而言,平和的心态是很重要的,一定要表述清晰。当然前提是头脑清晰。好的面试官会引导去挖掘你的闪光点,所以也不用怕有问题答不上来,实话说不会就好。当然,问什么会什么谁都喜欢。一定要像技术讨论一样去做面试。记得在Quora上看到一个Google员工回答面试心态时说道:**要想象自己已经进入了公司,而你的面试官就是你的同事,你们只不过是在聊一个平常的技术问题。**虽然还不能完全游刃有余,但渐渐正在往这个方向努力。

接着,就直接上技术问题。就笔试而言,更多地考察到了基础掌握的深度和一些平时容易忽略的知识点。涉及到的有:

  • HTTP请求跨域访问问题
  • 移动浏览器平台事件触发
  • Web Components 标准
  • 对象属性的操作
  • 二维矩阵展平
  • 数组基础操作api
  • 垂直水平居中的几种方式
  • 页面隐藏元素的几种方式
  • 事件代理
  • 斐波那契数列

阿里的笔试比较偏向于javascript方面的知识,css考察较少,也没有DOM操作之类的题目,但是css的考察都比较深入,自己也答得不是很全面。


电面方面,被问到比较印象深刻的知识点:

  • 排序问题,时间复杂度
  • 事件代理
  • 两列布局的实现
  • 两个排好序的数组,求其中位数
  • setTimeout(fn, 0)的意义
  • 前端性能优化的方式

收获:

大部分问题并不是很难,但是都需要有比较熟悉的掌握才能对答如流。我的问题就是出在对答如流上。知道坑在哪里,但是讲的不够清晰。规整来说,还是要多写,多整理。一个问题,一定不能浅尝辄止,遇到了就要把它吃透。

如何权衡想和做

在写下这一行字的时候,我已经删了不知几次第一句。时不时碎碎念起来的一个根本原因是没有思考。既然没有细致的技术思考,我就把这个issue作为开篇警示,甚至以后的Motion guide。重新审视下想和做的问题。

说起来,任何人在任何一个学习过程中,总是有两种情况:

一味天马飞行空,没有切实行动

这是我认识度比较高的一个问题。自己大多数时间有这种毛病。chrome打开了n多标签栏,有些甚至半个月后实在无法忍受才去按下一个ctrl+w,但当时找这篇技术blog的初衷也许已经忘了。漫漫的书签更是重灾区。这导致的一个直接原因便是生产力低下和“脑肌梗塞”。好像跟标题差的有点远,但反应的就是一个无法正确组织自己行动的问题。

resolve:

每天学习工作完成后,抽出一定的时间,整理一整天的收获,关闭每一个标签栏,以及chrome,一切不必要的繁琐生产环境。让第二天一开始的工作从清爽中开始。

闷头猛干老黄牛,**迟滞迟早low

这个一般发生在赶项目的时候。比如最近,一直在纠结和实现在线阅读器。等一回过神,发现已经过了好多天,知识和技术没有沉淀。

resolve:

每天早上不要急着工作,让思绪飞一会儿。想想到底要干什么。而不是闷头去找解决方案。

Motion List

这是一些技术点,或者是技术,或者是工具。都是自己听说过的,学习过的,了解过的,甚至只是听过名字但下一步想要了解学习的。越是深入,就标识越多的#

Angular(##
Ajax(###

Backbone.js

CSS(3)(#####

D3.js

Express(##

Git(###
Github(####

HTML(5)(#####
HTTP(###

JavaScript(######
jQuery(####

MySQL(#
meteor(#
mongo(#

Node.js(###

python(#
pdf.js(####
pdftk(##

SQL(###

WebStorm之效率提升

作为前端最便捷的IDE,webstorm撸起码来节奏地飞起。但是,能够完善地用起来也是需要一定的编码经验才能体会到。所以,写一些小的demo或者非大型工程的话,用sublime || atom 之类反而更方便。而且能更好地学习。

webstorm的一些经常使用的快捷操作:

打开文件:cmd+shift+o
查找类名:cmd+alt+o

[翻译]JavaScript的一些“最佳”实践

[翻译]A mostly reasonable approach to JavaScript

Types

  • Primitives:当操作原始值时是直接对它的值进行操作
    • string
    • number
    • boolean
    • null
    • undefined
  • Complex:当操作复杂类型时,是操作其值的引用
    • object
    • array
    • function

Objects

  • 使用字面量来创建对象

    // good
    var item = {};
  • 不要用保留字作为对象属性,在IE8中将报错

  • 使用可以理解的同义词代替保留字class ~ type / default ~ defaults

Arrays

  • 使用字面量来创建数组

  • 使用push方法在数组末尾新增元素,而不是直接使用arr.length

  • 当需要一个数组副本时用slice方法而不是for循环遍历每一个元素。

  • 把一个类数组对象转换为数组也用slice方法

    function trigger() {
      var args = Array.prototype.slice.call(arguments);
      ...
    }

Strings

  • ''单引号包裹字符串(嘿嘿,一直这么做的,nice)
  • 字符串多于100个字符应该写成多行,用+拼接(速度可能稍减,但可读性最好)
  • 当需要字符串拼接操作时,join('')优于+

Functions

  • 函数表达式
 // anonymous function expression
var anonymous = function() {
  return true;
};
// named function expression
var named = function named() {
  return true;
};

// immediately-invoked function expression (IIFE)
(function() {
  console.log('Welcome to the Internet. Please follow me.');
})();
  • 不要在一个非函数语句块儿内声明一个函数(if,while,for,etc),为函数声明个变量再使用。Note:函数声明不是一个语句。

    // bad
    if (currentUser) {
    function test() {
      console.log('Nope.');
    }
    }
    // good
    var test;
    if (currentUser) {
    test = function test() {
      console.log('Yup.');
    };
    }
  • 不要在函数内声明arguments参数,它将会覆盖每个函数作用域内的默认arguments对象。

    // bad
    function nope(name, options, arguments) {
    // ...stuff...
    }
    // good
    function yup(name, options, args) {
    // ...stuff...
    }

Properties

  • 访问对象属性时,尽量用.操作符。当属性是个变量时,再用[]

Variables

  • 始终不要忘记用var 来声明变量,以免污染全局作用域。
  • 每个变量用一个var,也就是说,不要进行联合声明。
// bad
var items = getItems(),
    goSportsTeam = true,
    dragonball = 'z';

// bad
// (compare to above, and try to spot the mistake)
var items = getItems(),
    goSportsTeam = true;
    dragonball = 'z';

// good
var items = getItems();
var goSportsTeam = true;
var dragonball = 'z';
  • 在变量声明区的最后声明未赋值的变量。以便于后期维护。
// bad
var i, len, dragonball,
    items = getItems(),
    goSportsTeam = true;

// bad
var i;
var items = getItems();
var dragonball;
var goSportsTeam = true;
var len;

// good
var items = getItems();
var goSportsTeam = true;
var dragonball;
var length;
var i;
  • 将变量赋值放在每个作用域开头,以避免变量声明和命名提升。但是要注意无意义的函数调用。
// bad
function() {
  test();
  console.log('doing stuff..');
  //..other stuff..
  var name = getName();
  if (name === 'test') {
    return false;
  }
  return name;
}

// good
function() {
  var name = getName();
  test();
  console.log('doing stuff..');
  //..other stuff..
  if (name === 'test') {
    return false;
  }
  return name;
}

// bad - unnecessary function call
function() {
  var name = getName(); 
  if (!arguments.length) {
    return false;
  }
  this.setFirstName(name);
  return true;
}

// good
function() {
  var name;
  if (!arguments.length) {
    return false;
  }
  name = getName();
  this.setFirstName(name);
  return true;
}

Hoisting

  • 变量声明会在每个作用域内提升至作用域头,但赋值还是在原处。
  • 匿名函数表达式会对变量名进行声明提升,但函数定义却还在原地。
 function example() {
  console.log(anonymous); // => undefined
  anonymous(); // => TypeError anonymous is not a function
  var anonymous = function() {
    console.log('anonymous function expression');
  };
}
  • 命名函数表达式,提升变量名声明,但函数名和函数体都不提升。
 function example() {
  console.log(named); // => undefined
  named(); // => TypeError named is not a function
  superPower(); // => ReferenceError superPower is not defined
  var named = function superPower() {
    console.log('Flying');
  };
}

// the same is true when the function name
// is the same as the variable name.
function example() {
  console.log(named); // => undefined
  named(); // => TypeError named is not a function
  var named = function named() {
    console.log('named');
  }
}
  • 函数声明的话,就函数名和函数体均提升
 function example() {
  superPower(); // => Flying

  function superPower() {
    console.log('Flying');
  }
}

Comparison Operators & Equality

  • ===!==而不是==,!=
  • 条件判断语句,比如if,会进行强制boolean转型,遵循以下简单规则:
    • object-----true
    • undefined-----false
    • null-----false
    • booleans
    • numbers----- +0,-0,NaN为false,其余true
    • strings----- ''为false,其余true
  • 根据以上,写简写就不要再自己加判断了
// bad
if (name !== '') {
  // ...stuff...
}
// good
if (name) {
  // ...stuff...
}
// bad
if (collection.length > 0) {
  // ...stuff...
}
// good
if (collection.length) {
  // ...stuff...
}

Blocks

  • 多行代码块儿就用{}
  • if...else的多行语句块,else放到if大括号语句块的结尾
// bad
if (test) {
  thing1();
  thing2();
}
else {
  thing3();
}

// good
if (test) {
  thing1();
  thing2();
} else {
  thing3();
}

Comments

  • /**...*/多行注释(webstorm默认行为),写上参数,返回值
  • //单行注释,单行注释在被注释行前单独一行,而且之前最好空一行。
 // bad
var active = true;  // is current tab

// good
// is current tab
var active = true;

// bad
function getType() {
  console.log('fetching type...');
  // set the default type to 'no type'
  var type = this._type || 'no type';

  return type;
}
// good
function getType() {
  console.log('fetching type...');

  // set the default type to 'no type'
  var type = this._type || 'no type';

  return type;
}
  • 给注释加上前缀:FIXME:(描述问题),TODO:(需要下一步实现的功能)

Whitespace

  • 两格缩进(这里貌似是不朽的圣战),ps:不过确实两格看起来舒适一些,而且有些模板(jade)不致冲突
  • {前加一个空格
  • 操作符用空格分开
  • 文件结尾一个换行符
// bad
(function(global) {
  // ...stuff...
})(this);

// bad
(function(global) {
  // ...stuff...
})(this);


// good
(function(global) {
  // ...stuff...
})(this);
  • 方法链式调用的时候,换行缩进,而且以点操作开头,不容易混淆。--这个jQuery比较多出现,原生还好
// bad
$('#items').find('.selected').highlight().end().find('.open').updateCount();

// bad
$('#items').
  find('.selected').
    highlight().
    end().
  find('.open').
    updateCount();

// good
$('#items')
  .find('.selected')
    .highlight()
    .end()
  .find('.open')
    .updateCount();

// bad
var leds = stage.selectAll('.led').data(data).enter().append('svg:svg').classed('led', true)
    .attr('width', (radius + margin) * 2).append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);

// good
var leds = stage.selectAll('.led')
    .data(data)
  .enter().append('svg:svg')
    .classed('led', true)
    .attr('width', (radius + margin) * 2)
  .append('svg:g')
    .attr('transform', 'translate(' + (radius + margin) + ',' + (radius + margin) + ')')
    .call(tron.led);
  • 一个语句块儿结束后,下一个语句之前,添一个空行。
// bad
if (foo) {
  return bar;
}
return baz;

// good
if (foo) {
  return bar;
}

return baz;

// bad
var obj = {
  foo: function() {
  },
  bar: function() {
  }
};
return obj;

// good
var obj = {
  foo: function() {
  },

  bar: function() {
  }
};

return obj;

Commas

  • 千万不要以逗号开头啊
  • 数组和对象最后一个元素后,不要加额外的逗号啊

Semicolons

要加,能省的地方也加。so,Yup.警卫分号也是个好习惯。

// bad
(function() {
  var name = 'Skywalker'
  return name
})()

// good
(function() {
  var name = 'Skywalker';
  return name;
})();

// good (guards against the function becoming an argument when two files with IIFEs are concatenated)
;(function() {
  var name = 'Skywalker';
  return name;
})();

Type Casting & Coercion

  • Strings类型的强制转换,放语句头做。
//  => this.reviewScore = 9;

// bad
var totalScore = this.reviewScore + '';

// good
var totalScore = '' + this.reviewScore;

// bad
var totalScore = '' + this.reviewScore + ' total score';

// good
var totalScore = this.reviewScore + ' total score';
  • parseInt数字转型时,始终不要忘带上基数。
var inputValue = '4';

// bad
var val = new Number(inputValue);

// bad
var val = +inputValue;

// bad
var val = inputValue >> 0;

// bad
var val = parseInt(inputValue);

// good
var val = Number(inputValue);

// good
var val = parseInt(inputValue, 10);
  • 当需要使用二进制转换以提升性能的时候,加上注释
// good
/**
 * parseInt was the reason my code was slow.
 * Bitshifting the String to coerce it to a
 * Number made it a lot faster.
 */
var val = inputValue >> 0;
  • 但是要注意,Numbers是64位值,但是位操作却总是返回一个32位整型,所以位转换操作不能操作大于32位以上的大整数。即:不能大于2147483647。
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
  • Booleans
var age = 0;

// bad
var hasAge = new Boolean(age);

// good
var hasAge = Boolean(age);

// good
var hasAge = !!age;

Naming Conventions

  • 避免单个字母的命名。
  • 当命名对象,函数,实例时使用驼峰式。
  • 构造函数和类的命名就使用大写命名。
  • 私有属性用单个下划线_
// bad
this.__firstName__ = 'Panda';
this.firstName_ = 'Panda';

// good
this._firstName = 'Panda';
  • 当保存一个this的引用时,用_this
// bad
function() {
  var self = this;
  return function() {
    console.log(self);
  };
}

// bad
function() {
  var that = this;
  return function() {
    console.log(that);
  };
}

// good
function() {
  var _this = this;
  return function() {
    console.log(_this);
  };
}
  • 总是给一个函数命名吧。
// bad
var log = function(msg) {
  console.log(msg);
};

// good
var log = function log(msg) {
  console.log(msg);
};
  • 如果当前文件导出一个单个类,那么文件名应该跟类名一致。
// file contents
class CheckBox {
  // ...
}
module.exports = CheckBox;

// in some other file
// bad
var CheckBox = require('./checkBox');

// bad
var CheckBox = require('./check_box');

// good
var CheckBox = require('./CheckBox');

Accessors

  • 属性的访问器函数不是必要的。
  • 如果需要,用getVal()setVal()
 // bad
dragon.age();

// good
dragon.getAge();

// bad
dragon.age(25);

// good
dragon.setAge(25);
  • 如果属性是布尔型,用isVal()hasValu()
// bad
if (!dragon.age()) {
  return false;
}

// good
if (!dragon.hasAge()) {
  return false;
}
  • 注意get(),set()要保持一致
function Jedi(options) {
  options || (options = {});
  var lightsaber = options.lightsaber || 'blue';
  this.set('lightsaber', lightsaber);
}

Jedi.prototype.set = function(key, val) {
  this[key] = val;
};

Jedi.prototype.get = function(key) {
  return this[key];
};

Constructors

  • 添加方法时,给prototype指派方法,但是不要重写prototype属性。(这个地方,主要是顾虑到原型链可能遭改变,但是注意下也是可以用的)
function Jedi() {
  console.log('new jedi');
}

// bad
Jedi.prototype = {
  fight: function fight() {
    console.log('fighting');
  },

  block: function block() {
    console.log('blocking');
  }
};

// good
Jedi.prototype.fight = function fight() {
  console.log('fighting');
};

Jedi.prototype.block = function block() {
  console.log('blocking');
};
  • 方法可以返回this使得可以进行链式调用
// bad
Jedi.prototype.jump = function() {
  this.jumping = true;
  return true;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
};

var luke = new Jedi();
luke.jump(); // => true
luke.setHeight(20); // => undefined

// good
Jedi.prototype.jump = function() {
  this.jumping = true;
  return this;
};

Jedi.prototype.setHeight = function(height) {
  this.height = height;
  return this;
};

var luke = new Jedi();

luke.jump()
  .setHeight(20);
  • 可以重写一个toString()这样的原始方法,但是要注意不要有额外的影响。
function Jedi(options) {
  options || (options = {});
  this.name = options.name || 'no name';
}

Jedi.prototype.getName = function getName() {
  return this.name;
};

Jedi.prototype.toString = function toString() {
  return 'Jedi - ' + this.getName();
};

Events

当给事件传递数据时,用一个hash对象而不是一个原始值。

// bad
$(this).trigger('listingUpdated', listing.id);

...

$(this).on('listingUpdated', function(e, listingId) {
  // do something with listingId
});

// good
$(this).trigger('listingUpdated', { listingId : listing.id });

...

$(this).on('listingUpdated', function(e, data) {
  // do something with data.listingId
});

Modules

  • 模块应该以!开始,确保,文件合并时,上一个文件在忘记结尾分号的时候也可用。
  • 模块以驼峰式来命名,
  • 增加一个noConflict()方法来导出先前版本的模块,然返回当前版本。
  • 总是声明use strict
// fancyInput/fancyInput.js

!function(global) {
  'use strict';

  var previousFancyInput = global.FancyInput;

  function FancyInput(options) {
    this.options = options || {};
  }

  FancyInput.noConflict = function noConflict() {
    global.FancyInput = previousFancyInput;
    return FancyInput;
  };

  global.FancyInput = FancyInput;
}(this);

jQuery

  • jQuery对象加一个$前缀
// bad
var sidebar = $('.sidebar');

// good
var $sidebar = $('.sidebar');
  • 缓存jQuery查到的DOM元素。(其实原生也一样)
// bad
function setSidebar() {
  $('.sidebar').hide();

  // ...stuff...

  $('.sidebar').css({
    'background-color': 'pink'
  });
}

// good
function setSidebar() {
  var $sidebar = $('.sidebar');
  $sidebar.hide();

  // ...stuff...

  $sidebar.css({
    'background-color': 'pink'
  });
}
  • 对DOM的查询,用级联的$('.sidebar ul')$('.sidebar > ul')
  • 对jQuery对象的查询时,再用find()方法
// bad
$('ul', '.sidebar').hide();

// bad
$('.sidebar').find('ul').hide();

// good
$('.sidebar ul').hide();

// good
$('.sidebar > ul').hide();

// good
$sidebar.find('ul').hide();

思考

这是一份javascript的代码规范,也是一些最佳实践。有一些编辑器可以帮忙做,但由于Javascript是一个动态性且包容性很强的语言(大多是浏览器的原因),仍需要对Javascript的模式有一定的了解,才能写出可读性好,可维护性强的javascript代码。

里面对自己感觉有启发意义或者还有所欠缺的建议加上了strong。希望能把代码写的更美一些。

ES6 In Depth: Iterators and the for-of loop

原文地址:https://hacks.mozilla.org/2015/04/es6-in-depth-iterators-and-the-for-of-loop/
本文仅供个人学习,禁止转载。

你是怎样遍历一个数组中的元素的?20年前,当JavaScript面世的时候,你或许是这样做的:

for (var index = 0; index < myArray.length; index++) {
    console.log(myArray[index]);
}

从ES5开始,你可以使用内建的forEach方法:

myArray.forEach(function (value) {console.log(value); });

这样简短了一些,但是有一个不大不小的缺点:你不能通过break中断循环,或者使用return语句从循环函数中返回。

肯定是有一个更好的for循环语法只遍历数组元素。for-in循环怎么样呢?

for (var index in myArray) {    // don't actually do this
    console.log(myArray[index]); 
}

从几个方面来说,这可不是一个好主意:

  • 代码中,赋值给index的是字符串”0”,”1”,”2”等,而不是数值。因为你或许并不希望字符串类型的运算,这是很不便利的。
  • 而且,循环体不仅在数组元素上执行,还会在一些增加的额外属性上执行。举例来说,如果你的数组有一个enumerable属性,myArray.name, 这个循环将额外执行一次,此时index == ’name’。甚至是在数组的原型链上可以访问到的属性。
  • 更恐怖的是,在某些环境下,这种代码以随机顺序遍历数组元素。
    总而言之,for-in是被设计用来在原生的有字符型键值的传统对象上工作的。对数组而言,它不是很好。

强大的for-of循环

还记得上周我承诺过说,ES6将会打破你固有的编写js代码的模式。好吧,成千上万的的网站依赖于for-in,即使它在数组上的表现并不怎么样。所以,在修复for-in使它在处理数组时更有效这个问题上毫无疑问。对ES6来说,仅有的一条途径来改善这个现状就是增加某种新的循环语法。

for (var value of myArray) {
	console.log(value);
}

额,看起来很不起眼,对吧。好,让我们且看看for-of是否有一些独特的技巧。现在来说,只关注这些就好:

  • 这是目前循环一个数组最简洁,最直接的语法
  • 它避免了所有for-in存在的缺陷
  • 不像forEach(),它支持break, continue, return

for-in循环是用来循环对象属性的,for-of循环是用来循环数据的——就像数组中的值。
但这不是全部。

其它集合也支持for-of

for-of不仅适用于数组。它在类数组对象上同样适用,比如DOM NodeLIsts。

而且同样适用于字符串,将字符看作是unicode字符的序列:

for (var chr of "😺😲") {
  alert(chr);
}

同样适用于Map和Set对象。
抱歉,你还没听说过Map和Set对象?它们是ES6的新特性。之后我们会发文讲述。如果你在其它语言有过使用Map和Set的经历,那就不会很奇怪了。

举例来说,一个Set对象便于消除重复。

// make a set from an array of words
var uniqueWords = new Set(words);

一旦你拿到一个Set,或许你想要循环它的内容,简单:

for (var word of uniqueWords) {
  console.log(word);
}

Map有些许的不同:它之中的数据由键值对组成,所以你将会想要通过解构来取出键值并赋给不同的变量:

for (var [key, value] of phoneBookMap) {
  console.log(key + "'s phone number is: " + value);
}

解构赋值是另外一个ES6的新特性。将来会有讲述。

现在而言,你只需知道:JS已经有一些不同的数据结构类型了,而且还有更多的在加入。for-of是设计用来给他们做循环的好方法。

for-of在原生传统对象上不起作用,但是如果你想要遍历一个对象的属性,你可以使用for-in或者内建的Object.keys()

// dump an object's own enumerable properties to the console
for (var key of Object.keys(someObject)) {
  console.log(key + ": " + someObject[key]);
}

揭开迷雾(兜帽之下)

“Good artists copy, great artists steal.” —Pablo Picasso

ES6中的一个现行主题是:所有增加到语言中的新特性并不是无中生有的。大部分都是在其他语言中被实践而且证实是有用的。

for-of循环来说,很像C++, Java, C#, Python中的循环语句。和它们一样,它在语言本身提供的或者标准库支持的几种不同的数据结构上都可以执行。但是它也是语言的一个扩展点。

正像for/forEach语句在其他语言的表现一样,**for-of完全按照方法调用的方式工作。**无论是Arrays, Maps, Sets还是我们刚才提到的其他一些对象也好,究其根本,他们都有一个iterator方法。

而且,还有另外的对象也可以有iterator方法:你能想到的所有对象。

就像你可以在任一对象上增加一个myObject.toString()方法,然后JS就知道怎样能够把这个对象转为一个字符串一样。你也可以增加一个myObject[Symbol.iterator]()方法在任一对象上,然后JS就知道该怎样遍历这个对象了。

举例来说,假设你使用jQuery,尽管你非常喜欢.each()方法,你也希望jQuery对象能够很好的使用for-of。怎么做呢:

// Since jQuery objects are array-like,
// give them the same iterator method Arrays have
jQuery.prototype[Symbol.iterator] =
  Array.prototype[Symbol.iterator];

哈,我知道你在想什么。那个[Symbol.iterator]语法看起来怪怪的。这里发生了什么?必须要搞清楚这个方法的命名。标准委员会,应该只是提到的.iterator()方法,但是,你的现存代码或许已经在许多对象中存在了.iterator()方法,那会变得很迷惑。所以标准使用了一个symbol而不是一个string来作为方法名。

Symbols也是ES6的新特性,我们将会在之后讨论它。暂时来说,你只需知道标准可以定义一系列的新的symbol,就像Symbol.iterator,而它负责保证与现有代码不会有冲突。这个权衡导致语法有点奇怪。但是这对出色的新特性和完美的向后兼容而言只是一点点的小代价。

一个有[Symbol.iterator]()方法的对象被称作可迭代的。接下来,我们会看到,可迭代对象这个概念在语言内多次出现,不仅仅是for-of,而且在Map, Set构造函数,解构赋值,和新的spread操作符。

可迭代对象

现在,有一个前所未有的机会来从无至有实现一个可迭代对象。下周我们来看到底为什么。为了完整性,我们来看一下一个可迭代对象长什么样。

一个for-of循环从调用在集合之上的[Symbol.iterator]()方法开始。这将返回一个新的可迭代对象。一个可迭代对象可以是任何有.next()方法的对象;for-of循环将重复地调用这个方法,直到通过循环。举个栗子:这是一个我能想到的最简单的可迭代对象:

var zeroesForeverIterator = {
  [Symbol.iterator]: function () {
    return this;
  },
  next: function () {
    return {done: false, value: 0};
  }
};

每次.next()方法调用,它都返回同样的结果,告诉for-of循环两件事情:

  1. 我们还没有完成迭代;
  2. 下一个value的值是0.
    这意味着for(value of zerosForeverIterator) { }将会是一个无限循环。当然,一个典型的迭代器不会那么简单。

这个迭代器设计,依赖于它的.done.value属性, 这个别的语言的迭代器工作原理不同。在Java里,迭代器有分离开的,hasNext()next()方法。在Python里,它们有一个单独的.next()方法,当在没有更多值的时候抛出stopIteration。但是所有这三种设计基本上都返回同样的信息。

一个迭代器对象也可以实现可选的.return().throw(exc)方法。for-of循环在提前退出循环的时候会调用.return(),由于异常情况,或者一个break或者return语句。一个迭代器当需要清理或者释放自身所占用的资源时,可以实现.return()方法。大多数的迭代器对象不需要实现它。.throw(exc)是一个更加特殊的栗子:for-of永远不会调用它。但是我们下周会获知更多关于它的信息。

现在我们有了所有的实现细节,我们可以拿到一个简单的for-of循环然后按照底层方法调用的方式重写它。

首先,for-of循环:

for (VAR of ITERABLE) {
  STATEMENTS
}

这里是一个相对简陋的等效实现,使用底层方法和一些临时变量:

var $iterator = ITERABLE[Symbol.iterator]();
var $result = $iterator.next();
while (!$result.done) {
  VAR = $result.value;
  STATEMENTS
  $result = $iterator.next();
}

这个代码没有显示.return()是怎么处理的。我们可以加上,但是我认为它将会迷惑到底发生了什么而不是阐明它。for-of是很方便使用的,但是在它背后发生了很多事情。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.