码迷,mamicode.com
首页 > 编程语言 > 详细

Top 10 JavaScript traps for a C# developer

时间:2014-05-30 00:38:22      阅读:360      评论:0      收藏:0      [点我收藏+]

标签:des   c   class   code   java   tar   

Top 10 JavaScript traps for a C# developer

If you are an experienced C# developer, coming into JavaScript world for application development, you will end up making few common mistakes. However some of the mistakes you would make are due to the basic differences between any strongly typed language [C#, Java etc.] and a dynamically typed language [JavaScript, Python etc]. Although dynamic feature was added to C# version 4.0, its initial design was based on static typing.

Note, I am primarily a .Net developer and have experience of developing web applications using JavaScript, and I admit that I made these mistakes when I started learning JavaScript. I spent good amount of time analyzing the root cause of the issues, just to realize that some of the mistakes were really due to my experience in C# language and assumption that JavaScript code would work exactly. I was wrong however. So in this article, I will cover top 10 JavaScript traps for a C# developer so that they don’t make the same mistakes which I did.

I assume that you have basic experience with C# language, so that we can focus more on JavaScript language in this article. With that, let’s jump into the traps.

1. Equality Operator

Most common trap between the two languages is the equality operator, also known as comparison operator. Unlike C# which has one equality operator [==], JavaScript has two [== and ===].

Let’s take a look at equality operator in C# first.

For predefined value types in C#, equality operator returns true if the values of its operands are equal, otherwise it returns false. Assuming you have basic understanding of C# language, below code snippet should be easy to understand.

Console.WriteLine("10 == 10 ? " + (10 == 10)); // returns true
Console.WriteLine("10 != 10 ? " + (10 != 10)); // returns false.
Console.WriteLine("10 != 20 ? " + (10 != 20)); // returns true. 

For reference types other than string, equality operator returns true if its two operands refer to the same object.
In the code snippet below, emp1 and emp2 are two different Employee instances, hence comparing two different instances in such case would return a false value.

var emp1 = new Employee();
var emp2 = new Employee();
Console.WriteLine("emp1 == emp2 ? " + (emp1 == emp2)); // returns false

In below code snippet, however, we have assigned emp2 instance variable to emp1, so both the instances are now pointing to same memory location. So comparing two instance in such case would return a true result.

emp1 = emp2;
Console.WriteLine("emp1 == emp2 ? " + (emp1 == emp2)); // returns true

For the string type, == compares the values of the strings. In the code snippet below, strings “A” and “B” are not same, comparing these two strings would return a false result.

Console.WriteLine("A == B ? " + ("A" == "B")); // returns false

In below code snippet, we have copied string “A” to temp variable and compared it with “A” string constant. Since both the strings contains same value, comparison in such case would return a true value.

var temp = string.Copy("A");
Console.WriteLine("A == A ? " + ("A" == temp));

In JavaScript however, equality operator works differently. Let’s understand the difference in these two equality operators first.

Equals (==) If the two operands are of same datatype, equality operator returns true if operand values are same, false otherwise.

console.log(‘10 == 10 ? ‘ + (10 == 10)); // returns true
console.log(‘"10" == "10" ? ‘ + ("10" == "10")); // returns true
console.log(‘true == true" ? ‘ + (true == true)); // returns true

If the two operands are NOT of the same datatype, JavaScript converts the operands and then applies comparison. If either operand is a number or a boolean or a string, the operands are converted to numbers if possible.

In below code snippets, string value “10″, boolean value ‘true’ and ‘false’ gets converted into a number before the comparison takes place. All the comparison statement below returns a true value.

console.log(‘10 == "10" ? ‘ + (10 == "10"));
console.log(‘1 == true ? ‘ + (1 == true));
console.log(‘0 == false ? ‘ + (0 == false));
console.log(‘0 == "" ? ‘ + (0 == ""));
console.log(‘0 == " " ? ‘ + (0 == " "));

If both operands are objects, then JavaScript compares internal references which are equal when operands refer to the same object in memory.

var x = { name: ‘Prasad‘ };
var y = { name: ‘Prasad‘ };
var z = x;

console.log(x == y); // returns false
console.log(x == z); // returns true

Strict Equal (===) Returns true if the operands are strictly equal with no type conversion.

In below code snippet, both the operands are of same data type with same value, all the comparison statements would return true result.

console.log(‘10 === 10 ? ‘ + (10 === 10));
console.log(‘"20" === "20" ? ‘ + ("20" === "20"));
console.log(‘true === true ? ‘ + (true === true));

Below code statement would return false result since the data type of the operands are different.

console.log(‘10 === "10" ? ‘ + (10 === "10"));
console.log(‘10 === "20" ? ‘ + (10 === "20"));
console.log(‘1 === true ? ‘ + (1 === true));
console.log(‘0 === false ? ‘ + (0 === false));
console.log(‘0 === "" ? ‘ + (0 === ""));
console.log(‘0 === " " ? ‘ + (0 === " "));
console.log(‘"" === " " ? ‘ + ("" === " "));

2. Variable Scope

C# allows programmer to declare a variable at different locations, which determines its scope. Variables that are defined at the class level are available to any non-static method within the class. Variables declared within a method’s code block are available for use by any other part of the method, including nested code blocks. And finally, if you declare a variable within a block construct such as an If statement, that variable’s scope is only until the end of the block.

In the code listing below variable favoriteCity is declared at class level, so it is accessible to all the methods in the class VariableScope. Considering its a static variable, it can be accessed inside a static or an instance method, however it wont be accessible using a class instance.

Variables declared at class level can be overridden in the functions. In below example, Main method overrides variable favoriteCity and sets it to “New York”. Since the class level variable is accessible to all the methods, PrintFavoriteCity function can access it. Any local variable declared in Main method or PrintFavoriteCity won’t be accessible outside method definition.

Finally, we have declared a welcomeMessage variable inside a if block. The scope of this variable is only within the if block and it wont be accessible outside the block, within Main method or PrintFavoriteCity method.

class VariableScope
{
    private static string favoriteCity = "London";
    static void Main()
    {
    Console.WriteLine("Your favorite city is {0}", favoriteCity);
    favoriteCity = "New York";
    PrintFavoriteCity();

    if (favoriteCity.Equals("New York"))
    {
            var welcomeMessage = "Welcome New Yorker";
        Console.WriteLine(welcomeMessage);
    }
    }

    static void PrintFavoriteCity()
    {
    Console.WriteLine("Your favorite city is {0}", favoriteCity);
    }
}

JavaScript has two scopes: global and local. A variable that is declared outside a function definition is a global variable, and its value is accessible and modifiable throughout your program. A variable that is declared inside a function definition is local. It is created and destroyed every time the function is executed, and it cannot be accessed by any code outside the function. JavaScript does not support block scope.

In the code listing below, favoriteCity variable is declared outside function definition, hence its scoped as global and can be accessed inside any function. Variable favoriteIndianCity is declared inside PrintFavoriteCity function, so its a local scope variable and cannot be accessed outside function definition. Finally we have declared a welcomeMessage variable inside an if block. Since JavaScript does not support block scoped variable, welcomeMessage variable can be accessed anywhere within the containing function.

var favoriteCity = "London";
        
function PrintFavoriteCity() {
    console.log(favoriteCity);

    var favoriteIndianCity = "Pune";
    console.log(favoriteIndianCity);
    
    if (true) {
    var welcomeMessage = "Hello dear traveler!";
    console.log(welcomeMessage);
    }

    welcomeMessage = "Hello dear traveler, welcome back! ";
    console.log(welcomeMessage);
}

3. For each

In C# foreach statement is used to repeat a group of embedded statements for each element in an array or a collection which implements IEnumerable or IEnumerable<T> interface. Most of the collection classes in C# like Array, List, Dictionary, HashSet etc implement these interfaces, so iterating over these collection using foreach statement is a common practice.

Iterating over string array collection

var rainbowColors = new[] { "Red", "Orange", "Yellow", "Green", "Blue", "Indigo", "Violet" };
foreach (var rainbowColor in rainbowColors)
{
    Console.WriteLine(rainbowColor);
}

Iterating over specialized collection – StringCollection

var cities = new StringCollection { "Pune", "London", "New York", "Mumbai" };
foreach (var city in cities)
{
    Console.WriteLine(city);
}

Iterating over Generic collection – List

var weekdays = new List(){"Mon", "Tue", "Wed", "Thur", "Fri", "Sat", "Sun"};
foreach (var weekday in weekdays)
{
    Console.WriteLine(weekday);
}

Unlike C#, JavaScript has three flavors of for each statements!.

for each…in : It is used to iterate a specified variable over all values of object’s properties. For each distinct property, a specified statement is executed. However, for each…in is deprecated as the part of ECMA-357 (E4X) standard. E4X support has been removed, but for each…in will not be disabled and removed because of backward compatibility considerations.

var sum = 0;
var obj = {prop1: 10, prop2: 20, prop3: 30};

for each (var item in obj) {
    sum += item;
}

print(sum); // prints "60", which is 10+20+30

for…in : It is used to iterates over property names in arbitrary order. Since the order is not consistent, this version should not be used to iterate over array elements.

let arr = [ 3, 5, 7 ];
arr.foo = "hello";

for (let i in arr) {
   console.log(i); // logs "0", "1", "2", "hello"
}

for…of : It is used to iterates over property values in consistent order. This version is suitable to iterate over array like elements, however this feature is yet to be implemented in all the browsers and is part of ECMA6 proposal.

let arr = [ 3, 5, 7 ];
arr.foo = "hello";

for (let i of arr) {
   console.log(i); // logs "3", "5", "7"
}

4. Switch statement

In C#, the switch statement is a control statement that selects a switch section to execute from a list of candidates. Each switch section contains one or more case labels followed by one or more statements.

The following example shows a simple switch statement that has five switch sections. Each switch section has one case label, such as case 10, case 20 etc. Each case label specifies a constant value. The switch statement transfers control to the switch section whose case label matches the value of the switch expression. If no case label contains a matching value, control is transferred to the default section, if there is one. If there is no default section, no action is taken and control is transferred outside the switch statement.

Console.WriteLine("Enter your age");
var age = int.Parse(Console.ReadLine());

switch (age)
{
    case 10:
    Console.WriteLine("Drink milk");
    break;
    case 20:
    case 30:
    Console.WriteLine("Take Latte or beer");
    break;
    case 50 - 10:
    Console.WriteLine("You can have Whiskey");
    break;
    case 50:
    Console.WriteLine("Take medicine");
    break;
    default:
    Console.WriteLine("Invalid input");
    break;
}

JavaScript is a dynamically typed language. In other words, language doesn’t enforce you to declare the type during variable declarations and you can easily change the data type later. As we discussed earlier, in regular if statement comparison, data type doesn’t matter unless you are using strict comparison that specifically check for data type.

y = 5;
x = ‘5‘;
if(x == y){
    console.log("they‘re the same"); // logs ‘they‘re the same‘
}

The exception is case values in the switch statement. For the case to be a match, the data types must match. Think for it as switch statements including === (strict equal) instead of == (equal) for case comparisons.

y = 5;
switch(y){
    case ‘5‘:
    console.log("y is 5"); // this won‘t log the message
}

However, main difference in JavaScript switch statement is that, each section can contain an expression or a constant. Note, C# language accepts only constant value in switch expression. Below JavaScript code snippet demonstrates case expression. Note the switch(true) statement, which always execute in this case and the actual value of input is used in case expression.

var input = prompt("enter your age");
switch (true) {
    case input > "10" && input < 20:     
    console.log(‘Take Milk‘);     
    break;     

     case input > "21" && input <= 40:     
     console.log("Take Beer");     
     break;     

     case input >= 41 && input <=50 :     
     console.log("Take Whiskey");     
     break;     

     case input > 51:
     console.log("Take Medicine");
     break;

     default:
     console.log("Invalid input");
     break;
}

5. Function overloading

In C#, function overloading is, when you have two or more methods with the same name but different signatures. At compile time, the compiler works out which one it’s going to call, based on the compile time types of the arguments and the target of the method call.

In below code snippet, we have two forms of Add function and depending on the type and number of arguments, appropriate Add function gets called.

static void Main()
{
    Console.WriteLine("10 + 20 = " + Add(10,20));
    Console.WriteLine("10 + 20 + 30 = " + Add(10, 20, 30));
    Console.ReadLine();
}

static int Add(int number1, int number2)
{
    return number1 + number2;
}

static int Add(int number1, int number2, int number3)
{
    return number1 + number2 + number3;
}

JavaScript does not support function overloading!! Even though everything in JavaScript is an Object in itself, the language does not support some of the common object oriented language feature like function overloading.

So what happens if you declare two functions with the same name? Lets see it in action.

In the code block defined below, we have declared two Add functions which takes different number of parameters. JavaScript unfortunately overrides the Add function defined earlier using 2 parameters with the Add function defined later using 3 parameters, so for a calling application only one Add function is available.


So the question is, what happens when we call Add function with 2 arguments, when its signature contains three arguments. Well, in above case, parameter num3 gets initialized to undefined, which is our next trap in the list!

6. undefined function parameter

In C#, once you define a function with a given number of parameters, the calling code has to pass same number of arguments, unless any of the parameters are set as optional. For example, WelcomeUser function define in below code takes two parameters – userName and welcomeMessage.

static void WelcomeUser(string userName, string welcomeMessage = "Welcome")
{
    Console.WriteLine("{0} {1}!", welcomeMessage, userName);
}

The welcomeMessage parameter was declared as an optional parameter, so the calling code may not necessarily pass its value, in which case its default value ‘Welcome’ will be considered during function execution. If the calling code passes welcomeMessage argument, it will override its default value while calling the function.

static void Main(string[] args)
{
    WelcomeUser("Prasad");
    WelcomeUser("Colin", "Good Morning");
    // WelcomeUser(); // this won‘t compile as userName is mandatory parameter
}

JavaScript however works in a different manner. It does not enforce user to pass values for all the parameters during function call. In such case, a variable that has not been assigned a value is of type undefined.

Let’s take a look at the example. WelcomeUser function defined below takes two parameters userName and welcomeMessage. In the first call, we are passing arguments ‘Scott’ and ‘Good Morning’ to WelComeUser function, and it logs it as expected. No surprises here.

Now, when we call the function without passing same number of arguments, JavaScript treats that argument as undefined. So in second call, when we pass ‘Prasad’ as an usreName argument, welcomeMessage gets initialized to undefined, so it displays the output as ‘Prasad undefined!’

Similarly, when we call the function without passing any arguments, both the parameters gets initialized to undefined and it displays the output as ‘undefined undefined!’

function WelcomeUser(userName, welcomeMessage) {
    console.log(userName + " "  + welcomeMessage + "!");
}
WelcomeUser("Scott", "Good Morning");
WelcomeUser("Prasad");
WelcomeUser();

Point to note that, unlike C# compiler, JavaScript compiler wont display any compile time error for undefined parameters. So now the question is how to handle undefined parameters? You can use undefined and the strict equality and inequality operators to determine whether a variable has a value or not. So let’s modify above code to do the same.

function WelcomeUser(userName, welcomeMessage) {
    if (userName === undefined) {
        userName = "Admin";
    }
    if (welcomeMessage == undefined) {
        welcomeMessage = "Welcome";
    }
    console.log(userName + " " + welcomeMessage + "!");
}

As you can easily notice, in the above code snippet, we have set userName to ‘Admin’ and welcomeMessage to ‘Welcome’, if calling code doesn’t pass the argument value.

7. Truthy and Falsy

In C#, true and false values are always represented by a boolean variable or an boolean expression. The controlling conditional expression of an if-statement is a boolean-expression, which must return either true or false. If the condition doesn’t return a boolean value, a compile time error occurs. Let’s look into the code now.

The displayFlag boolean variable is initialized to true, so the statement enclosed in if block will always execute and outputs “Display flag is true”.

bool displayFlag = true;
if (displayFlag)
{
    Console.WriteLine("Display flag is true");
}

Below code block shows simplest example of boolean expression, which must return either true or false value [True in this case].

if (2 > 1)
{
    Console.WriteLine("2 is greater than 1");
}

As we discussed in the earlier sections, C# is a statically typed language, so the operands in a boolean expression should be compatiable for equality operation. For e.g. comparing a int variable with a string would result into a compile time error as shown in below example.

var firstNumber = 10;
var secondNumber = "10";
if (firstNumber == secondNumber) { } // compile time error

To ensure the controlling conditional expression of an if-statement return a boolean-expression, we need to typecast the if statement as shown below

var firstNumber = 10;
var secondNumber = "10";
var equalNumber = ((bool)(firstNumber.ToString() == secondNumber));

In JavaScript, 0, false, ”, undefined, null, NaN are falsy values. All other value are truthy.

if (!0) {
    console.log("0 is falsy");
}
 
if (!false) {
    console.log("false is falsy");
}
 
if (!‘‘) {
    console.log("‘‘ is falsy");
}
 
if (undefined) {
    console.log(‘undefined is falsy‘);
}
 
if (!null) {
    console.log(‘null is falsy‘);
}
 
if (!0/0) {
    console.log(‘NaN is falsy‘);
}

Note that, a space character [‘ ‘] is a trythy value in JavaScript, and so does the Infinity.

if (1 / 0) {
    console.log(‘Infinity is truthy‘);
}
 
if (‘ ‘) {
    console.log("‘ ‘ is truthy");
}

8. Curly braces and return statement

Both C# and JavaScript languages provides a return statement to return the execution control to the caller, however there is one subtle gotcha when you used it along with curly braces in JavaScript.

You will find endless arguments on web on ‘whether the curly brace should appear on the same line as block construct [class, function etc.] or whether they should appear on their own line’. In C#, it doesn’t matter really. It’s a person preference to have it on the same line or new line, however I would suggest you to choose one and stick to it.

Add function defined in below code listing contains curly braces on new line, while the GetDefaultCategory function contains opening curly brace and return statement on different lines, which C# compiler will happily compile.

public static int Add(int num1, int num2)
{
    return num1 + num2;
}
 
public static dynamic GetDefaultCategory(){
return
    new
    {
            Name = "General"
    };
}

JavaScript however behaves differently in this case. The Add function is similar to C# version and will always display the addition of two numbers passed in. However GetDefaultCategory function defined below will simply return the call to the caller without returning the object literal. This is due to automatic semicolon insertion feature of JavaScript. In this case, since we have opening curly brace on the next line after return statement, JavaScript compiler will insert a semicolon after return statement causing it to exit from the function without returning any value.

function Add(num1, num2)
{
    return num1 + num2;
}
 
function GetDefaultCategory() {
return
{
    name: "General"
}
};

This can easily get more difficult as compiler doesn’t return any error in this case, however caller will get a null reference rather than the object literal. To avoid such kind of situation, always use curly brace on the same line as return statement or block construct, as shown below

function Add(num1, num2){
    return num1 + num2;
}
 
function GetDefaultCategory() {
return {
    name: "General"
}
};

9. this keyword

The this keyword in C# is generally used for two purposes

  1. Access the current instance of the class
  2. To add extension methods on existing types without creating new types.

Let’s discuss both of these options in detail

Following code listing contains an Employee class with two properties which has been protected by private setters, so only the parameterized constructor can initialize these values. Note that the constructor uses this.Id syntax to access the property on a given instance. Similarly, overridden ToString method retrieves class properties using this keyword.

public sealed class Employee
{
    public int Id { get; private set; }
    public string Name { get; private set; }

    public Employee(int id, string name)
    {
    this.Id = id;
    this.Name = name;
    }

    public override string ToString()
    {
        return string.Format("ID : {0} , Name : {1}", this.Id, this.Name);
    }
}

C# 3 introduced ‘Extension Method’ concept in the language. Extension methods enable you to “add” methods to existing types without creating a new derived type, recompiling, or otherwise modifying the original type. This includes even adding extension method on sealed type like string or Employee class defined in earlier code listing. Below code listing adds an extension method PrintNameAndLength to Employee class. Note the this keyword used in the PrintNameAndLength signature, which denotes extension method on Employee type.

public static class EmployeeExtension
{
    public static string PrintNameAndLength(this Employee emp)
    {
    return emp.Name + " : " + emp.Name.Length;
    }
}

Once declared, you can invoke it as a normal instance method as shown in below code example

var emp = new Employee(1, "Prasad");
Console.WriteLine(emp.PrintNameAndLength());

The most common extension methods are the LINQ standard query operators that add query functionality to the existing System.Collections.IEnumerable and System.Collections.Generic.IEnumerable types.

10. Hoisting

As we examined in earlier sections, JavaScript supports only function level scope as compared to C# which has different scope rules [class, method, block]. However, it’s worth to find out how JavaScript handles the scoping.

In JavaScript, all the variable declared inside a function share same scope. Behind the scene, JavaScript hoists all the variable declaration to the top of the function and initialize them to undefined. Their assignment still remain on the same line where it was declared. This process is known as ‘Variable Hoisting’.

Let’s take a look at simple JavaScript function defined below.

function doSomething() {
     console.log(someVariable); //undefined
 
     var someVariable = 100;
     console.log(someVariable); // 100
 
     if (true){
         someVariable = 200;
         console.log(someVariable); // 100
     }
}

JavaScript hoist the variable someVariable to the top of the function doSomething> and initialize it to undefined. Below is the code definition after the hoisting is done. Since variable was gets hoisted to the top of the function, it can be accessed from anywhere inside the function. This is the main reason why JavaScript does not support block scoping.

function doSomething() {
    var someVariable = undefined;
    console.log(someVariable); //undefined
 
    someVariable = 100;
    console.log(someVariable); // 100
 
    if (true){
        someVariable = 200;
        console.log(someVariable); // 100
    }
}

And then JavaScript does function hoisting as well! However, the hoisting rules for variable and functions are different. JavaScript provides two ways to define a function in a program – Function Expression and Function Statement. The easiest way to tell them apart is, if it starts with the function keyword, then it is a function statement.

try {
    printOne();
    printTwo();
 
} catch (e) {
    console.log(e.message);
}
 
// Function Expression
var printOne = function () {
    console.log("One");
}
 
// Function Statement
function printTwo() {
    console.log("Two");
}

During function hoisting process, function statement is transformed behind the scenes into a function expression and then both the variable and the assignment are hoisted to the top of the function scope. So the function gets converted as shown below

var printOne = undefined,
    printTwo = undefined;
 
printTwo = function(){
    console.log("Two");
}
 
try {
    printOne();
    printTwo();
} catch (e) {
    console.log(e.message);
}
 
printOne = function () {
    console.log("One");
}

Note that, function expression follows same rule as variable hoisting, but function statement behaves differently.

Summary

Ah!, we did it. Here comes the summary bubuko.com,布布扣 I hope this post helped you to understand basic differences between JavaScript and C# languages, and common traps associated with it.

Please provide your feedback in the comments section below

 

 

source: http://www.codetails.com/2014/05/27/top-10-javascript-traps-for-a-c-developer/

Top 10 JavaScript traps for a C# developer,布布扣,bubuko.com

Top 10 JavaScript traps for a C# developer

标签:des   c   class   code   java   tar   

原文地址:http://www.cnblogs.com/glenblogs/p/3757960.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!