[关闭]
@fengfeng 2015-03-16T07:42:48.000000Z 字数 6219 阅读 1099

js note

note


As Phil Karlton once said, There are only two hard things in Computer Science: cache invalidation and naming things.

from
#
http头,meta中相同的声明浏览器处理的优先级
To sum up, conforming user agents must observe the following priorities when determining a document's character encoding (from highest priority to lowest):

An HTTP "charset" parameter in a "Content-Type" field.
A META declaration with "http-equiv" set to "Content-Type" and a value set for "charset".
The charset attribute set on an element that designates an external resource.
In addition to this list of priorities, the user agent may use heuristics and user settings. For example, many user agents use a heuristic to distinguish the various encodings used for Japanese text. Also, user agents typically have a user-definable, local default character encoding which they apply in the absence of other indicators.

User agents may provide a mechanism that allows users to override incorrect "charset" information. However, if a user agent offers such a mechanism, it should only offer it for browsing and not for editing, to avoid the creation of Web pages marked with an incorrect "charset" parameter.

在写复杂的 JavaScript 应用之前,充分理解原型链继承的工作方式是每个 JavaScript 程序员必修的功课。要提防原型链过长带来的性能问题,并知道如何通过缩短原型链来提高性能。
更进一步,绝对不要扩展内置类型的原型,除非是为了和新的JavaScript 引擎兼容。

hasOwnProperty 函数

为了判断一个对象是否包含自定义属性而不是原型链上的属性, 我们需要使用继承自 Object.prototype 的 hasOwnProperty 方法。

注意: 通过判断一个属性是否 undefined 是不够的。 因为一个属性可能确实存在,只不过它的值被设置为 undefined。

hasOwnProperty 是 JavaScript中唯一一个处理属性但是不查找原型链的函数。

typeof 操作符

typeof 唯一有用的地方

  1. typeof foo !== 'undefined'

toType

  1. var toType = function(obj) {
  2. return ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase()
  3. }

instanceof 操作符

instanceof 操作符应该仅仅用来比较来自同一个 JavaScript 上下文的自定义对象; 如果用来比较内置类型,将会和 typeof 操作符 一样用处不大。
//null instanceof Object ==>false
// typeof null ==>object

字符串转换为数字的常用方法:

  1. +'010' === 10
  2. Number('010') === 10
  3. parseInt('010', 10) === 10 // 用来转换为整数
  4. +'010.2' === 10.2
  5. Number('010.2') === 10.2
  6. parseInt('010.2', 10) === 10

转换为布尔型

通过使用 否 操作符两次,可以把一个值转换为布尔型。

  1. !!'foo'; // true
  2. !!''; // false
  3. !!'0'; // true
  4. !!'1'; // true
  5. !!'-1' // true
  6. !!{}; // true
  7. !!true; // true

eval

eval 只在被直接调用并且调用函数就是 eval 本身时,才在当前作用域中执行。

直接调用eval时,为直接调用,而使用表达式计算得到的eval是间接调用.
eg.

  1. global = (function(){ return this || (0,eval)('this'); }());
  2. //eval('this')和(0,eval)('this')的区别是,一个是在当前执行环境下直接调用,一个表达式计算得到的eval是间接调用,是在全局执行环境下执行,后面的调用方式才可百分百确定指向的是全局宿主对象
  1. var foo = 1;
  2. function test() {
  3. var foo = 2;
  4. var bar = eval;
  5. bar('foo = 3');//window.eval
  6. return foo;
  7. }
  8. test(); // 2
  9. foo; // 3

undefined 和 null

JavaScript 有两个表示‘空’的值,其中比较有用的是 undefined。

undefined 的值

undefined 是一个值为 undefined 的类型。

这个语言也定义了一个全局变量,它的值是 undefined,这个变量也被称为 undefined。 但是这个变量不是一个常量,也不是一个关键字。这意味着它的值可以轻易被覆盖。

ES5 提示: 在 ECMAScript 5 的严格模式下,undefined 不再是 可写的了。 但是它的名称仍然可以被隐藏,比如定义一个函数名为 undefined。
下面的情况会返回 undefined 值:

处理 undefined 值的改变
由于全局变量 undefined 只是保存了 undefined 类型实际值的副本, 因此对它赋新值不会改变类型 undefined 的值。

然而,为了方便其它变量和 undefined 做比较,我们需要事先获取类型 undefined 的值。

为了避免可能对 undefined 值的改变,一个常用的技巧是使用一个传递到匿名包装器的额外参数。 在调用时,这个参数不会获取任何值。

  1. var undefined = 123;
  2. (function(something, foo, undefined) {
  3. // 局部作用域里的 undefined 变量重新获得了 `undefined` 值
  4. })('Hello World', 42);

另外一种达到相同目的方法是在函数内使用变量声明。

  1. var undefined = 123;
  2. (function(something, foo) {
  3. var undefined;
  4. ...
  5. })('Hello World', 42);

这里唯一的区别是,在压缩后并且函数内没有其它需要使用 var 声明变量的情况下,这个版本的代码会多出 4 个字节的代码。

译者注:这里有点绕口,其实很简单。如果此函数内没有其它需要声明的变量,那么 var 总共 4 个字符(包含一个空白字符) 就是专门为 undefined 变量准备的,相比上个例子多出了 4 个字节。

null 的用处

JavaScript 中的 undefined 的使用场景类似于其它语言中的 null,实际上 JavaScript 中的 null 是另外一种数据类型。

*它在 JavaScript 内部有一些使用场景(比如声明原型链的终结 Foo.prototype = null),但是大多数情况下都可以使用 undefined 来代替。*

自动分号插入

JavaScript 解析器在遇到由于缺少分号导致的解析错误时,会自动在源代码中插入分号。

  1. (function(window, undefined) {
  2. function test(options) {
  3. log('testing!')
  4. (options.list || []).forEach(function(i) {
  5. })
  6. options.value.test(
  7. 'long string to pass here',
  8. 'and another long string to pass'
  9. )
  10. return
  11. {
  12. foo: function() {}
  13. }
  14. }
  15. window.test = test
  16. })(window)
  17. (function(window) {
  18. window.someLibrary = {}
  19. })(window)

下面是解析器"猜测"的结果。

  1. (function(window, undefined) {
  2. function test(options) {
  3. // 没有插入分号,两行被合并为一行
  4. log('testing!')(options.list || []).forEach(function(i) {
  5. }); // <- 插入分号
  6. options.value.test(
  7. 'long string to pass here',
  8. 'and another long string to pass'
  9. ); // <- 插入分号
  10. return; // <- 插入分号, 改变了 return 表达式的行为
  11. { // 作为一个代码段处理
  12. foo: function() {}
  13. }; // <- 插入分号
  14. }
  15. window.test = test; // <- 插入分号
  16. // 两行又被合并了
  17. })(window)(function(window) {
  18. window.someLibrary = {}; // <- 插入分号
  19. })(window); //<- 插入分号

前置括号

在前置括号的情况下,解析器不会自动插入分号。

  1. log('testing!')
  2. (options.list || []).forEach(function(i) {})
  3. //==>
  4. log('testing!')(options.list || []).forEach(function(i) {})

建议
- 绝对不要省略分号,前置括号前面主动添加分号;

  1. function test(xx){
  2. //xxxxxx
  3. }
  4. ;(function(){ /*todo*/ }()) //主动在括号前添加分号

隐藏使用 eval

setTimeout 和 setInterval 也接受第一个参数为字符串的情况。 这个特性绝对不要使用,因为它在内部使用了 eval。

注意: 由于定时器函数不是 ECMAScript 的标准,如何解析字符串参数在不同的 JavaScript 引擎实现中可能不同。 事实上,微软的 JScript 会使用 Function 构造函数来代替 eval 的使用。

  1. function foo() {
  2. // 将会被调用
  3. }
  4. function bar() {
  5. function foo() {
  6. // 不会被调用
  7. }
  8. setTimeout('foo()', 1000);
  9. }
  10. bar();

由于 eval 在这种情况下不是被直接调用,因此传递到 setTimeout 的字符串会自全局作用域中执行; 因此,上面的回调函数使用的不是定义在 bar 作用域中的局部变量 foo。

建议不要在调用定时器函数时,为了向回调函数传递参数而使用字符串的形式。
  1. function foo(a, b, c) {}
  2. // 不要这样做
  3. setTimeout('foo(1,2, 3)', 1000)
  4. // 可以使用匿名函数完成相同功能
  5. setTimeout(function() {
  6. foo(a, b, c);
  7. }, 1000)

注意: 虽然也可以使用这样的语法 setTimeout(foo, 1000, a, b, c), 但是不推荐这么做,因为在使用对象的属性方法时可能会出错。 (译者注:这里说的是属性方法内,this 的指向错误)
结论

绝对不要使用字符串作为 setTimeout 或者 setInterval 的第一个参数, 这么写的代码明显质量很差。当需要向回调函数传递参数时,可以创建一个匿名函数,在函数内执行真实的回调函数。

另外,应该避免使用 setInterval,因为它的定时执行不会被 JavaScript 阻塞。

ie attachEvent

When binding handlers with .attachEvent, the this value of the handler will not be the element

http://quirksmode.org/dom/core/

childNodes VS children

.childNodes is a property of Node.
childNodes will give you all kinds of nodes(will give you a list, that contains text nodes (even if they are filled with whitespaces), comments and all kinds of other node types)

.children is a property of an Element.
Element.children returns only element children
children will give you only element nodes

nodeType value

1 ELEMENT_NODE
2 ATTRIBUTE_NODE
3 TEXT_NODE
4 CDATA_SECTION_NODE
5 ENTITY_REFERENCE_NODE
6 ENTITY_NODE
7 PROCESSING_INSTRUCTION_NODE
8 COMMENT_NODE
9 DOCUMENT_NODE
10 DOCUMENT_TYPE_NODE
11 DOCUMENT_FRAGMENT_NODE
12 NOTATION_NODE

setAttribute('classs','') Vs obj.className=''

In IE the Javascript setAttribute("class", ) or getAttribute("class") method doesn't works or gives error in some versions. So instead of that one case use the "className" attribute for a given DOM element.

substr substring

The difference is in the second argument. The second argument to substring is the index to stop at (but not include), but the second argument to substr is the maximum length to return.

Links?

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/substr

https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/String/substring

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注