Advanced Javascript: Objects, Arrays, and Array-Like objects

Javascript objects and arrays are both incredibly useful. They’re also incredibly easy to confuse with each other. Mix in a few objects that look like arrays and you’ve got a recipe for confusion!

We’re going to see what the differences between objects and arrays are, how to work with some of the common array-like objects, and how to get the most performance out of each.

What Objects Are

A javascript object is a basic data structure:

1 
2  var  basicObj  =  {};  //  an empty object
3  //  {} is a shortcut for "new Object()"
4 
5  basicObj.suprise =   " cake! " ;
6 
7  basicObj[ ' suprise ' ];  //  returns "cake!"

 

Using {} instead of new Object(); is know as “Object Literal” syntax.

 

 1  var  fancyObj  =  {
 2 
 3      favoriteFood:  " pizza " ,
 4 
 5      add:  function (a, b){
 6 
 7           return  a  +  b;
 8      }
 9  };
10 
11  fancyObj.add( 2 , 3 );  //  returns 5
12 
13  fancyObj[ ' add ' ]( 2 , 3 );  //  ditto.

 

 

As you can see, and probably already knew, properties can be accessed a couple of different ways. However, it’s an important point that we’ll come back to in a minute.

Everything in javascript is an object. Everything. Arrays, functions, even numbers! Because of this, you can do some really interesting things, such as modifying the prototypes of Objects, Arrays, etc.

 1 
 2  //  an example of something you probably shouldn't do. Ever. Seriously.
 3 
 4  Number.prototype.addto  =   function (x){
 5 
 6       return   this   +  x;
 7 
 8  }
 9 
10  ( 8 ).addto( 9 );  //  returns 17
11 
12  //  other variations:
13 
14  8 .addto( 9 ); & nbsp;
15  //  gives a syntax error, because the dot is assumed to be a decimal point
16 
17  8 [ ' addto ' ]( 9 ); & nbsp;
18  //  works but is kind of ugly compared to the first method
19 
20  var  eight  =   8 ;
21  eight.addto( 9 ); & nbsp;  //  works

 

What Arrays Are

Javascript arrays are a type of object used for storing multiple values in a single variable. Each value gets numeric index and may be any data type.

1  var  arr  =  [];   //  this is a shortcut for new Array();
2 
3  arr[ 0 =   " cat " ;
4  arr[ 1 =   " mouse " ;

 

See how that syntax is so similar to the syntax used for setting object properties? In fact, the only difference is that objects use a string while arrays use a number. This is why arrays get confused with objects so often.

Length

Arrays have a length property that tells how many items are in the array and is automatically updated when you add or remove items to the array.

1  var  arr  =  [];
2 
3  arr[ 0 =   " cat " //  this adds to the array
4  arr[ 1 =   " mouse " //  this adds to the array
5  arr[ " favoriteFood " =   " pizza " //  this DOES NOT add to the array
6  //  setting a string parameter adds to the underlying object
7 
8  arr.length;  //  returns 2, not 3

 

The length property is only modified when you add an item to the array, not the underlying object.

The length is always 1 higher than the highest index, even if there are actually fewer items in the array.

1 
2  var  arr  =  [];
3 
4  arr.length;  //  returns 0;
5 
6  arr[ 100 =   " this is the only item in the array " ;
7 
8  arr.length;
9  //  returns 101, even though there is only 1 object in the array

 

This is somewhat counter-intuitive. PHP does more what you would expect:

1  <? php
2 
3  arr  =  array();
4 
5  arr[ 100 =   " php behaves differently " ;
6 
7  sizeof(arr);  //  returns 1 in PHP
8 
9  ?>

 

You can manually set the length also. Setting it to 0 is a simple way to empty an array.

In addition to this length property, arrays have lots of nifty built in functions such as push(), pop(), sort(), slice(), splice(), and more. This is what sets them apart from Array-Like Objects.

 

Array-like Objects

Array-like objects look like arrays. They have various numbered elements and a length property. But that’s where the similarity stops. Array-like objects do not have any of Array’s functions, and for-in loops don’t even work!

You’ll come across these more often than you might expect. A common one is the arguments variable that is present inside of every js function.

Also included in the category are the HTML node sets returned by document.getElementsByTagName(), document.forms, and basically every other DOM method and property that gives a list of items.

1 
2  document.forms.length;  //  returns 1;
3 
4  document.forms[ 0 ];  //  returns a form element.
5 
6  document.forms.join( " " );  //  throws a type error. this is not an array.
7 
8  typeof  document.forms;  //  returns "object"

 

Did you know you can send any number of parameters you want to a javascript function? They’re all stored in an array-like object named arguments.

 1 
 2  function  takesTwoParams(a, b){
 3 
 4       //  arguments is an&nbsp; array-like variable inside of all functions
 5       //  arguments.length works great
 6 
 7      alert ( " you gave me  " + arguments.length + "  parameters " ); & nbsp; 
 8 
 9       for (i = 0 ; i <  arguments.length; i ++ ){
10 
11          alert( " parameter  "   +  i  +   "  =  "   +  arguments[i]); 
12 
13      }
14  }
15 
16  takesTwoParams( " one " , " two " , " three " );
17  //  alerts "you gave me 3 parameter",
18  //  then "parameter 0 = one"
19  //  etc. 

 

This works great. But that’s about as far as you can go with array-like objects. The flowing example does not work:

1 
2  function  takesTwoParams(a, b){
3 
4      alert( "  your parameters were  "   +  arguments.join( " " ));
5       //  throws a type error because arguments.join doesn't exist
6  }

 

So what can you do?

Well you could make your own join() function, but that adds a lot of unnecessary overhead to your code because it has to loop over everything. If only there were a quick way to get an array out of an array like object…

It turns out there is.

The array functions can be called on non-array objects as long as you know where to find the function (usually they’re attached to the array, but this isn’t an array remember ;)

Prototype to the win:

1  function  takesTwoParams(a, b){
2 
3       var & nbsp;args & nbsp; =& nbsp;Array.prototype.slice.call(arguments);
4 
5      alert( "  your parameters were  "   +  args.join( " " ));
6       //  yay, this works!
7 
8  }

 

Let’s take a look at that a bit more in-depth:

Array: This object is the original array that all other arrays inherit their properties from.

Array.prototype:This gives us access to all the methods properties that each array inherits

Array.prototype.slice: The original slice method that is given to all arrays via the prototype chain. We can’t call it directly though, because when it runs internally, it looks at the this keyword, and calling it here would make this point to Array, not our arguments variable.

Array.prototype.slice.call(): call() and apply() are prototype methods of the Function object, meaning that they can be called on every function in javascript. These allow you to change what the this variable points to inside a given function.

And finally, you get a regular array back! This works because javascript returns a new object of type Array rather than whatever you gave it. This causes a lot of headaches for a few people who are trying to make subclasses of Array, but it’s very handy in our case!

Gotchas

First, in Internet Explorer, DOM NodeLists are not considered to be javascript objects, so you cannot call Array.prototype.slice on them. If you want an array, you’ll have to loop through it the old fashioned way. Or use a hybrid function that tries it the fast way first, then the slow way if that doesn’t work.

 1  function  hybridToArray(nodes){
 2       try {
 3           //  works in every browser except IE
 4           var  arr  =  Array.prototype.slice.call(nodes);
 5           return  arr;
 6      }  catch (err){
 7           //  slower, but works in IE
 8           var  arr  =  [],
 9              length  =  nodes.length;
10           for ( var  i = 0 ; i  <  length; i ++ ){
11              arr.push(nodes[i]);
12          }
13           return  arr;
14      }
15  }

 

See an example here: http://nfriedly.com/demos/ie-nodelist-to-array.

Second, arrays are objects, so you can do this, but it can get you some serious inconsistencies:

 1 
 2  arr  =  [];
 3 
 4  arr[ 0 =   " first element " //  adds item to the array
 5 
 6  arr.length;  //  returns 1
 7 
 8  arr.two  =   " second element " //  adds an item to the underlying object that array is built on top of.
 9 
10  arr.length;  //  still returns 1 !
11 
12  //  BUT...
13  for (i  in  arr){
14 
15       //  this will hit both 0 and "two"
16 
17  }

 

A better solution: wrap arrays in an object if you need both worlds

This is basically a less efficient method of the array subclassing links I mentioned above. While less efficient, it has the advantage of being simple and reliable.

That said, I wouldn’t recommend that you use this in most cases due to issues with speed and extra code requirements. It’s provided here as an example.

 1  //  an example of a wrapper for an array.
 2  //  not recommended for most situations.
 3 
 4  var  ArrayContainer  =   function (arr){
 5 
 6       this .arr  =  arr  ||  [];
 7 
 8       this .length  =   this .arr.length;
 9 
10  };
11 
12  ArrayContainer.prototype.add =& nbsp;  function (item){
13 
14      index  =   this .arr.length;
15 
16       this .arr[index]  =  item;
17 
18       this .length  =   this .arr.length;
19 
20       return  index;
21 
22  };
23 
24  ArrayContainer.prototype.get =& nbsp;  function (index){
25 
26       return   this .arr[index];
27 
28  };
29 
30  ArrayContainer.prototype.forEach =& nbsp;  function (fn){
31 
32       if ( this .arr.forEach)  this .arr.forEach(fn); //  use native code if it's there
33 
34       else  {
35 
36           for (i  in   this .arr){
37 
38              fn( i,  this .arr[i],  this .arr );
39 
40          }
41      }
42  };
43 
44  var  mySuperDooperArray  =   new  ArrayContainer();

 

Now that your array is (somewhat) protected on the inside, you can loop through it’s items with forEach() and know that they will match it’s length. You can also add arbitrary properties to ArrayContainer or mySuperDooperArray and they won’t get pulled into your forEach() loop.

This example could be extended to completely protect the array if the need arose.

An Even Better Solution: Hire a javascript expert.

nFriedly Web Development is a top ranked Javascript and AJAX ninja with an extensive portfolio of proven results. I can bring your project to life and make it run faster than you ever imagined.  Get in touch with me or get a free instant estimate for new projects.

转载于:https://www.cnblogs.com/Lion5859/archive/2010/03/05/1678876.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值