hywilliam / hywilliam.github.io Goto Github PK
View Code? Open in Web Editor NEWmy blog
my blog
eclipse, myeclipse 7 (考试用), idea
ArrayList 数据类型
Thinking in, 核心卷
方法调用, 静态成员变量, 静态方法
类成员变量, 实例化
为声明的对象分配内存空间
析构
package pkg1[.pkg2[.pkg3]]
public private protected default
Q: java的数据类型有哪些?
Q: 为什么分为基本类型和引用类型?
Q: 面向对象问题:权限限定符有几个?
final类,不能被继承。final方法,不能被重写。
extends, super
abstract, 单例模式(创建型),模板方法模式
interface
#1.8 新特性
Thread
使用vi也一年有余了,但是可能在日常使用中过于满足了,只是顺手了一些基本操作,虽然不影响正常的编码。但还是想再挖掘一些更加功效的使用出来。在此做一下记录:
在日常的学习工作中遇到的URL相关的问题,基本就是两个,一个是整体的解析,一个是查询字段的分离。下面来进行下前端URL的一些知识整理。
比较经典的URL解析方法:
/**
* 正则方法:大神的正则匹配方案,看得头疼脑热。
* 传入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()
。
URL相关的解析处理,无外乎正则匹配和字符串操作。但是要明晰的是,URL的几大部分,以https://bob:[email protected]:8080/file;p=1?q=2#third
为例,从左至右分别是:
清晰了URL的结构,那无论是要怎么操作都能得心应手。
其实之前也已经有过两次阿里内推电话面试的经历了。但是无奈当时积累有限,做不出有效的总结。相信好的总结是下一步继续进步的阶梯。
首先,总的来说,经过最近这几次,收获是颇丰的。不仅让自己知道了一些深浅,也不再像第一次电面时那么紧张了。就电话面试而言,平和的心态是很重要的,一定要表述清晰。当然前提是头脑清晰。好的面试官会引导去挖掘你的闪光点,所以也不用怕有问题答不上来,实话说不会就好。当然,问什么会什么谁都喜欢。一定要像技术讨论一样去做面试。记得在Quora上看到一个Google员工回答面试心态时说道:**要想象自己已经进入了公司,而你的面试官就是你的同事,你们只不过是在聊一个平常的技术问题。**虽然还不能完全游刃有余,但渐渐正在往这个方向努力。
接着,就直接上技术问题。就笔试而言,更多地考察到了基础掌握的深度和一些平时容易忽略的知识点。涉及到的有:
阿里的笔试比较偏向于javascript方面的知识,css考察较少,也没有DOM操作之类的题目,但是css的考察都比较深入,自己也答得不是很全面。
电面方面,被问到比较印象深刻的知识点:
收获:
大部分问题并不是很难,但是都需要有比较熟悉的掌握才能对答如流。我的问题就是出在对答如流上。知道坑在哪里,但是讲的不够清晰。规整来说,还是要多写,多整理。一个问题,一定不能浅尝辄止,遇到了就要把它吃透。
在写下这一行字的时候,我已经删了不知几次第一句。时不时碎碎念起来的一个根本原因是没有思考。既然没有细致的技术思考,我就把这个issue作为开篇警示,甚至以后的Motion guide。重新审视下想和做的问题。
说起来,任何人在任何一个学习过程中,总是有两种情况:
这是我认识度比较高的一个问题。自己大多数时间有这种毛病。chrome打开了n多标签栏,有些甚至半个月后实在无法忍受才去按下一个ctrl+w,但当时找这篇技术blog的初衷也许已经忘了。漫漫的书签更是重灾区。这导致的一个直接原因便是生产力低下和“脑肌梗塞”。好像跟标题差的有点远,但反应的就是一个无法正确组织自己行动的问题。
每天学习工作完成后,抽出一定的时间,整理一整天的收获,关闭每一个标签栏,以及chrome,一切不必要的繁琐生产环境。让第二天一开始的工作从清爽中开始。
这个一般发生在赶项目的时候。比如最近,一直在纠结和实现在线阅读器。等一回过神,发现已经过了好多天,知识和技术没有沉淀。
每天早上不要急着工作,让思绪飞一会儿。想想到底要干什么。而不是闷头去找解决方案。
这是一些技术点,或者是技术,或者是工具。都是自己听说过的,学习过的,了解过的,甚至只是听过名字但下一步想要了解学习的。越是深入,就标识越多的#
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(###
作为前端最便捷的IDE,webstorm撸起码来节奏地飞起。但是,能够完善地用起来也是需要一定的编码经验才能体会到。所以,写一些小的demo或者非大型工程的话,用sublime || atom 之类反而更方便。而且能更好地学习。
webstorm的一些经常使用的快捷操作:
打开文件:cmd+shift+o
查找类名:cmd+alt+o
使用字面量来创建对象
// good
var item = {};
不要用保留字作为对象属性,在IE8中将报错
使用可以理解的同义词代替保留字class ~ type / default ~ defaults
使用字面量来创建数组
使用push
方法在数组末尾新增元素,而不是直接使用arr.length
当需要一个数组副本时用slice
方法而不是for循环遍历每一个元素。
把一个类数组对象转换为数组也用slice
方法
function trigger() {
var args = Array.prototype.slice.call(arguments);
...
}
''
单引号包裹字符串(嘿嘿,一直这么做的,nice)+
拼接(速度可能稍减,但可读性最好)join('')
优于+
// 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...
}
.
操作符。当属性是个变量时,再用[]
。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;
}
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');
}
}
===
和!==
而不是==
,!=
if
,会进行强制boolean转型,遵循以下简单规则:
// bad
if (name !== '') {
// ...stuff...
}
// good
if (name) {
// ...stuff...
}
// bad
if (collection.length > 0) {
// ...stuff...
}
// good
if (collection.length) {
// ...stuff...
}
{}
if...else
的多行语句块,else
放到if大括号语句块的结尾// bad
if (test) {
thing1();
thing2();
}
else {
thing3();
}
// good
if (test) {
thing1();
thing2();
} else {
thing3();
}
/**...*/
多行注释(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:
(需要下一步实现的功能){
前加一个空格// bad
(function(global) {
// ...stuff...
})(this);
// bad
(function(global) {
// ...stuff...
})(this);↵
↵
// good
(function(global) {
// ...stuff...
})(this);↵
// 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;
要加,能省的地方也加。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;
})();
// => 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;
2147483647 >> 0 //=> 2147483647
2147483648 >> 0 //=> -2147483648
2147483649 >> 0 //=> -2147483647
var age = 0;
// bad
var hasAge = new Boolean(age);
// good
var hasAge = Boolean(age);
// good
var hasAge = !!age;
_
。// 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');
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];
};
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();
};
当给事件传递数据时,用一个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
});
!
开始,确保,文件合并时,上一个文件在忘记结尾分号的时候也可用。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);
$
前缀// bad
var sidebar = $('.sidebar');
// good
var $sidebar = $('.sidebar');
// 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'
});
}
$('.sidebar ul')
或$('.sidebar > ul')
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。希望能把代码写的更美一些。
原文地址: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]);
}
从几个方面来说,这可不是一个好主意:
还记得上周我承诺过说,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
不仅适用于数组。它在类数组对象上同样适用,比如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
循环两件事情:
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
是很方便使用的,但是在它背后发生了很多事情。
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.