JavaScript Tips for Novices, Acolytes, and Gurus

转载 2007年09月13日 12:36:00

JavaScript Tips for Novices, Acolytes, and Gurus
By Kris Kowal | Published: August 27, 2007 - 03:48PM CT

JavaScript, with its death grip on the Interwebs and every AJAX developer's language of only choice, is getting hot. With roll-overs, pop-ups, and menus either solved or relegated to CSS behaviors, XMLHttpRequests have made JavaScript once again a language of innovation. This article is meant to offer a tidbit of idiomatic advice for people who know JavaScript or want to know JavaScript coming from Java, C, Python, Perl, or PHP.

Novice: objects and associative arrays
Coming from Java, you might expect JavaScript to provide a base type, like Object. Coming from most languages, you might expect JavaScript to provide a dictionary, hash-table, or associative array type like Perl's %hash type, Python's dict type, PHP's array type, or Java's Map interface. JavaScript kills two birds with one stone, and I mean knocks them both dead. Object is the common, ancestral prototype of most instances. They are also used for String to Object mappings.

JavaScript provides a shorthand syntax for Object initialization, much like Perl and Python associative arrays.

 foo =  Object();
 foo = ;

Also, item indexing and member selection are equivalent.

foo.a == foo;

Since you can only use Strings as keys, indexing an Object on another Object implies that JavaScript will convert the index to a string using toString.

foo1 == foo(1).toString() == foo;

If you need a real hash mapping like Python or Java, you should find a library that provides one. Since JavaScript implementations don't all provide a mechanism for overloading item indexing (nor an equivalent property system like Python's or Ruby's) and no JavaScript implementation provides a default hash algorithm for objects, a good library will provide an associative array type that includes functions like getItem, setItem, hasItem, and delItem, and a general hash algorithm that returns good default hashes for every built-in type and uses polymorphic hash member functions.

Novice: cute type conversions

JavaScript provides valueOf and toString member functions for all objects. However, literal numbers, booleans, strings, undefined, and null are distinct from their object counterparts. For example, typeof new Number(1) == 'object' whereas typeof 1 == 'number'. However, there are some cute ways to implicitly and reliably convert any object to a literal number, literal boolean, or literal string.

You can convert any object to a number by adding it to zero.

0 + foo

You can convert any object to a string by adding it to a null string.

 + foo

However, strings and numbers are special. If you add a string and a number, the resultant type depends on whether the string is empty. An empty string gets coerced to the number zero. Otherwise, the zero gets coerced to a string and the addition performs concatenation.

0 +  == 0
 + 0 == 0
1 +  == 1
 + 1 == 1
0 +  == 
 + 0 == 

You can convert any object to a boolean, true or false value by negating it twice.


Novice: iteration

Coming from Java or C, JavaScript has a fun variation on the for loop. Coming from Perl, PHP, or Python, the familiar for loop has a subtle quirk. You can use a for loop to run a block repeatedly, once through for each member (items.member) and item (items['item']) of an Object. The iterand will be the index of the item, not the item itself.

 ( index  items) 
   item = itemsindex;

You should use a traditional, C-style for-loop for iterating Array objects. Bearing in mind that, in JavaScript, members and items are equivalent, the for loop will iterate over both numeric indices and named members, with the exception of built-in members like toString or exec. Some libraries controversially add member functions to the Array prototype. Sometimes this causes the for (var i in array) to iterate on these member functions in addition to the numbers. This is the pattern you should use to avoid getting member functions when you iterate on an Array:

 ( i = 0; i < items.length; i++) 
   item = itemsi;

Of course, these libraries and new browsers also provide alternate iteration mechanisms that are arguably more elegant. With recent versions of Firefox and libraries like Prototype, you get forEach iteration, which involves an anonymous function.

items.forEach( (item) 

Acolyte: anonymous functions

The redeeming grace of JavaScript is its provision of anonymous functions with full closures. In JavaScript, functions are objects. Programmers can pass functions as arguments. Furthermore, the function's scope includes all of the names in the scope in which it was declared. Coupled with the facts that functions are declared at run time and that local variables can stick around long after a function returns, closures provide a wealth of options for programmers. An exhaustive compendium of all the fun uses for closures would be far beyond the scope of this article, so here's a canonical example for you to ponder: a range generator.

 range =  (start, stop, step) 
     at = start;
    start += step;
     (at < stop)  at;
 next = range(0, 10, 2); 

The first call of next returns 0. The following times you call next it returns 2, 4, 6, and 8. Thereafter, calling next will throw an Error. This is because the local variables of range, the one time you've called it, remain in memory as long as next exists. The anonymous function that range returns is a closure: both the code of the function and a reference to the scope in which the function was declared. The returned function object effectively holds the range "function allocation record" in memory. Thus, the value of start persists across calls to next.

Acolyte: enclosure

In JavaScript's top scope, variables you declare with var are members of the window. To get a bit more privacy with your variables, you should use a closure by declaring an anonymous function and immediately calling it. Since calling functions can have unfortunate side-effect of switching your context object to the global context, use call to send this into your closure.

( () 

Another handy use for enclosures is to make using with and var behave deterministically and intuitively. The with block pushes an Object onto the scope chain. That is, members of a given object become local variables in the given block.

 (: 10) 
  a == 10;

However, when you declare variables with var inside a with block, the variables should be declared in the function block scope and a variable by the same name should be initialized in the with block scope. However, all bets are off depending on what browser runs the script. Using an enclosure inside all with blocks will force var declarations to operate in the innermost scope.

 (: 10) 
   a = 20;

Acolyte: context object manipulation

JavaScript provides a context object, this. In the global context, this is the window. Also, by default, this is the window when you call a function.

 bar =  ()  ;
bar() == ;

There are two ways to send other objects as the context object into a function. The first is to call a function as a member of an object.

 foo = : bar; == foo;

The second way to send an object to a function as its context object is explicit. You can use the method's first argument to send in an arbitrary object. call accepts the context object followed by any arguments you want to pass in normally., 0, 1, 2, ...);

Acolyte: variadic arguments

Coming from C, variadic arguments are the va_arg and ... syntax trick left over from ANSI C that allow functions like printf to accept an arbitrary number of arguments. In Python, you get variadic arguments and keywords using * and ** in your declarations and invocations. In JavaScript, like Perl, functions implicitly accept any number of arguments. You can access these variadic argument lists using the arguments variable inside your functions.

Consider a trivial max function that returns the largest of two numbers.

.max =  (a, b) 
   (a > b)  a;

max can use the arguments to read any number of arguments.

.max =  () 
   items = ;
   ( member  items) 
     item = itemsmember;
     (basis ===  || item > basis) 
      basis = item;

If you want to pass variadic arguments to a function from an arbitrary number of items in an Array, you can use the Function.apply function. Like call, apply accepts the context object as its first argument, followed by a single Array containing whatever arguments to you want to pass.

max.apply(, 10, 30, 20) == 30;

Guru: binding

You've likely noticed that the context object a function receives depends on the invocation syntax. Binding a function to an object assures that you receive a particular object. Here's a sample bind function.

 bind =  (context, functor) 
     functor.apply(context, );

Guru: lazy function definition

Peter Michaux recently documented and named the "Lazy Function Definition Pattern" wherein you determine the behavior of a function the first time the user calls it. This is handy for choosing among cross-platform code paths. Consider this function that gets the value of PI by calculating it once, then simply returning it after each successive call.

 getPi =  () 
   pi = calculatePi();
  getPi =  () 

Guru: polymorphic callable objects

Supposing you were writing a type system, you might want objects of all your types to have the option of being callable, and for the call behavior to be redefinable in sub-types. One fun way to do this is to always use Function instead of Object as your base type.

 callableType =  (constructor) 
     callableInstance =  () 
       callableInstance.callOverload.apply(callableInstance, );
    constructor.apply(callableInstance, );


JavaScript is a simple, powerful language made complex by a lack of guarantees, subtle variations of its implementation, and a propensity for silently ignoring errors. However, for the time being, JavaScript is the only language we have for cross-browser web development. By subscribing to some simple patterns, we can avoid some unfortunate surprises and build power-tools using power-tools in our collective JavaScript programming adventure.

Javascript Tips & Tricks

前端开发规范系列文章之Javascript Tips and Tricks,本意是写成常用代码收集、常用技巧整理的文章,感觉“常用代码大全”太土、“实用代码整理”有失偏颇,“提示与技巧”不够稳重,所以...
  • whqet
  • whqet
  • 2015年02月20日 05:54
  • 6360


  • lzlchangqi
  • lzlchangqi
  • 2016年10月16日 17:45
  • 732


// js函数实现中英文判断处理function tips(title, id) { var width = 40; var xx = 0; var returntitle = ""; for ( v...
  • gaochunhu
  • gaochunhu
  • 2011年04月04日 21:57
  • 1318


  • u012526003
  • u012526003
  • 2015年12月15日 18:58
  • 811

easyui tips使用实例

{ field:'name', title:'用户名', sortable:true, formatter:function(value,row){   var content = '' +...
  • qq277798882
  • qq277798882
  • 2017年05月14日 13:52
  • 466

一些技巧吧!Unity Tips(日常使用)

孙广东 2015.10.30 1、按组件名称搜索 场景的hierarchy 层次结构, 就是得到 使用了这个组件的对象 2、如何查找文档快捷方式(就是很快的方式找到 组件的文档) ...
  • u010019717
  • u010019717
  • 2015年10月30日 08:51
  • 3357


1. HTML标签大小写不敏感,属性名和属性值大小写敏感
  • ymjring
  • ymjring
  • 2012年07月30日 11:46
  • 1527


1、 性能测试的目的:通过测试确认软件是否满足产品的性能需求,同时发现系统中存在的性能瓶颈,起到优化系统的目的。2、 性能测试指标的来源:测试的依据是产品的需求规格说明书;如果用户没有提出性能指标则根...
  • Smilings
  • Smilings
  • 2006年11月20日 16:47
  • 3140

移动端 Tips插件代码

  • sszcome
  • sszcome
  • 2017年03月22日 19:19
  • 290


  • AC_great
  • AC_great
  • 2015年03月25日 11:17
  • 1027
您举报文章:JavaScript Tips for Novices, Acolytes, and Gurus