作用域链: 每一段 JavaScript 代码都有一个与之关联的作用域链。这个作用域链是一个对象列表或者链表,这组对象定义了这段代码“作用域中”的变量。当 JavaScript 需要查找变量 x 值的时候(变量解析) 它会从链的第一个对象开始查找,如果这个对象有一个名为 x 的属性,则会直接使用这个属性的值,如果不存在,JavaScript 会继续查找链上的下一个对象。以此类推。如果作用域链上不存在 x ,就认为这段代码作用域链上不存在 x,并最终跑出一个引用错误(ReferenceError)的异常。
functioneventfn(e){ var e = e || window.event; var target = e.target || e.srcElement; if (matchSelector(target, selector)) { if(fn) { fn.call(target, e); } } } } /** * only support #id, tagName, .className * and it's simple single, no combination */ functionmatchSelector(ele, selector) { // if use id if (selector.charAt(0) === '#') { return ele.id === selector.slice(1); } // if use class if (selector.charAt(0) === '.') { return (' ' + ele.className + ' ').indexOf(' ' + selector.slice(1) + ' ') != -1; } // if use tagName return ele.tagName.toLowerCase() === selector.toLowerCase(); }
// bad var errorMessage = 'This is a super long error that was thrown because of Batman. When you stop to think about how Batman had anything to do with this, you would get nowhere fast.';
// bad var errorMessage = 'This is a super long error that was thrown because \ of Batman. When you stop to think about how Batman had anything to do \ with this, you would get nowhere \ fast.';
// good var errorMessage = 'This is a super long error that was thrown because ' + 'of Batman. When you stop to think about how Batman had anything to do ' + 'with this, you would get nowhere fast.';
messages = [{ state: 'success', message: 'This one worked.' }, { state: 'success', message: 'This one worked as well.' }, { state: 'error', message: 'This one did not work.' }];
length = messages.length;
// bad functioninbox(messages) { items = '<ul>';
for (i = 0; i < length; i++) { items += '<li>' + messages[i].message + '</li>'; }
return items + '</ul>'; }
// good functioninbox(messages) { items = [];
for (i = 0; i < length; i++) { // use direct assignment in this case because we're micro-optimizing. items[i] = '<li>' + messages[i].message + '</li>'; }
// bad // make() returns a new element // based on the passed in tag name // // @param {String} tag // @return {Element} element functionmake(tag) {
// ...stuff...
return element; }
// good /** * make() returns a new element * based on the passed in tag name * * @param {String} tag * @return {Element} element */ functionmake(tag) {
// bad functiongetType() { console.log('fetching type...'); // set the default type to 'no type' var type = this.type || 'no type';
return type; }
// good functiongetType() { console.log('fetching type...');
// set the default type to 'no type' var type = this.type || 'no type';
return type; }
给注释增加 FIXME 或 TODO 的前缀可以帮助其他开发者快速了解这是一个需要复查的问题,或是给需要实现的功能提供一个解决方式。这将有别于常见的注释,因为它们是可操作的。使用 FIXME -- need to figure this out 或者 TODO -- need to implement。
使用 // FIXME: 标注问题。
1 2 3 4 5 6 7
functionCalculator() {
// FIXME: shouldn't use a global here total = 0;
returnthis; }
使用 // TODO: 标注问题的解决方式。
1 2 3 4 5 6 7
functionCalculator() {
// TODO: total should be configurable by an options param this.total = 0;
Edition 5 clarifies the fact that a trailing comma at the end of an ArrayInitialiser does not add to the length of the array. This is not a semantic change from Edition 3 but some implementations may have previously misinterpreted this.
// 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;
(function(){ var video = document.getElementById('video'); var canvas = document.getElementById('canvas'); var canvasContext = canvas.getContext('2d'); var audio_context;
audio_context = new AudioContext; __log('Audio context set up.'); __log('navigator.getUserMedia ' + (navigator.getUserMedia ? 'available.' : 'not present!')); } catch (e) { alert('No web audio support in this browser!'); }
function B(){ A.call(this); // 核心 // ... } var proto = inherit(Super.prototype); // 核心 proto.constructor = Sub; // 核心 Sub.prototype = proto; // 核心,完善原型链 var b = new B(); alert(b.val);