开发者

Refactoring JavaScript and PHP code [Job Interview]

recently I had a job interview. I had two tasks:

1) to refactor a JavaScript code

// The library 'jsUtil' has a public function that compares 2 arrays, returning true if
// they're the same. Refactor it so it's more robust, performs better and is easier to maintain.
/**
  @name jsUtil.arraysSame
  @description Compares 2 arrays, returns true if both are comprised of the same items, in the same order
  @param {Object[]} a Array to compare with
  @param {Object[]} b Array to compare to
  @returns {boolean} true if both contain the same items, otherwise false
  @example
  if ( jsUtil.arraysSame( [1, 2, 3], [1, 2, 3] ) ) {
    alert('Arrays are the same!');
  }
*/
// assume jsUtil is an object

jsUtil.arraysSame = function(a, b) {
  var r = 1;
  for (i in a) if ( a[i] != b[i] ) r = 0;
    else continue;
    return r;
}

2) To refactor a PHP function that checks for a leap year

<?php
/*
  The class 'DateUtil' defines a method that takes a date in the format DD/MM/YYYY, extracts the year
  and works out if it is a leap year. The code is poorly written. Refactor it so that it is more robust
  and easier to maintain in the future.

  Hint: a year is a leap year if it is evenly divisible by 4, unless it is also evenly
  divisible by 100 and not by 400.
*/

class DateUtil {
    function notLeapYear ($var) {
        $var = substr($var, 6, 4);
        if (! ($var % 100) && $var % 400) {
            return 1;
        }
        return $var % 4;
    }
}


$testDates = array('03/12/2000', '01/04/2001', '28/01/2004', '29/11/2200');

/* the expected result is
* 03/12/2000 falls in a leap year
* 01/04/2001 does not fall in a leap year
* 28/01/2004 falls in a leap year
* 29/11/2200 does not fall in a leap year
*/
?>

<? $dateUtil = new DateUtil(); ?>
<ul>
  <? foreach ($testDates as $date) { ?>
    <li><?= $date ?> <?= ($dateUtil->notLeapYear($date) ? 'does not fall' : 开发者_JAVA技巧'falls') ?> in a leap year</li>
  <? } ?>
</ul>

I think I cope with the task but I am not quite sure, I still don't have an answer from them and it's been about a week. Could you give an example of your approach to this tasks? I'd really appreciate. Later I can post my solutions/code.

OK here are my answers to the questions.

<?php // Always use full/long openning tags not 

$start = microtime(true);

class DateUtil {

    /**
     * The date could be used in other 
     * class methods in the future.
     * Use just internally.
     **/
    var $_date; 

    /**
     * The constructor of the class takes
     * 1 argument, date, as a string and sets
     * the object parameter _date to be used
     * internally. This is compatable only in PHP5
     * for PHP4 should be replaced with function DateUtil(...)
     */
    public function __construct( $date = '' ) {
        $this->_date = $date;
    }

    /**
     * Setter for the date. Currently not used.
     * Also we could use _set magical function.
     * for PHP5.
    **/
    public function setDate( $date = '' ) {
        $this->_date = $date;
    }

    /**
     * Gettre of the date. Currently not used.
     * Also we could use _get magical function.
     * for PHP5.
    **/
    public function getDate() {
        return $this->_date;
    }

    public function isLeapYear( $year = '' ) {
        // all leap years can be divided through 4
        if (($year % 4) != 0) {
            return false;
        }

        // all leap years can be divided through 400
        if ($year % 400 == 0) {
            return true;
        } else if ($year % 100 == 0) {
            return false;
        }

        return true;
    }
}

$dates = array('03/12/2000', '01/04/2001', '30/01/2004', '29/11/2200');
$dateUtil = new DateUtil();

foreach($dates as $date) {
    /** 
     * This processing is not done in the class
     * because the date format could be different in 
     * other cases so we cannot assume this will allways 
     * be the format of the date
     * 
     * The php function strtotime() was not used due to 
     * a bug called 2K38, more specifically dates after and 2038
     * are not parsed correctly due to the format of the UNIX 
     * timestamp which is 32bit integer.
     * If the years we use are higher than 1970 and lower
     * than 2038 we can use date('L', strtotime($date));
    **/
    $year = explode('/', $date);
    $year = $year[2];
    $isLeap = $dateUtil->isLeapYear($year);

    echo '<pre>' . $date . ' - ';
    echo ($isLeap)? 'Is leap year': 'Is not leap year';
    echo '</pre>';
}

echo 'The execution took: ' . (microtime(true) - $start) . ' sec';
?>

JavaScript

/***************************************************/

jsUtil = new Object();

jsUtil.arraysSame = function(a, b) {


    if( typeof(a) != 'object') {
        // Check if tepes of 'a' is object
        return false;
    } else if(typeof(a) != typeof(b)) {
        // Check if tepes of 'a' and 'b' are same
        return false;
    } else if(a.length != b.length) {
        // Check if arrays have different length if yes return false
        return false;
    }

    for(var i in a) {
        // We compare each element not only by value
        // but also by type so 3 != '3'
        if(a[i] !== b[i]) {
            return false;
        }
    }

    return true;
}

// It will work with associative arrays too
var a = {a:1, b:2, c:3};
var b = {a:1, b:2, c:3};    // true
var c = {a:1, b:2, g:3};    // false
var d = {a:1, b:2, c:'3'};  // false

var output = '';

output += 'Arrays a==b is: ' + jsUtil.arraysSame( a, b );
output += '\n';
output += 'Arrays a==c is: ' + jsUtil.arraysSame( a, c );
output += '\n';
output += 'Arrays a==d is: ' + jsUtil.arraysSame( a, d );

alert(output);


Iterate arrays using a for loop rather than for...in. If the arrays are different, you want to return as quickly as possible, so start with a length comparison and return immediately you come across an element that differs between the two arrays. Compare them using the strict inequality operator !==. Iterate backwards through the array for speed and to minimise the number of variables required by assigning a's length to i and reusing i as the iteration variable.

This code assumes that the parameters a and b are both supplied and are both Array objects. This seems to be implied by the question.

var jsUtil = jsUtil || {};

jsUtil.arraysSame = function(a, b) {
    var i = a.length;
    if (i != b.length) return false;
    while (i--) {
        if (a[i] !== b[i]) return false;
    }
    return true;
};


For the PHP version:

class DateUtil {
    function LeapYear ($var) {
        $date = DateTime::CreateFromFormat($var, 'd/m/Y');
        return($date->format('L')); // returns 1 for leapyear, 0 otherwise
    }
    function notLeapYear($var) {
        return(!$this->LeapYear($var)) {
    }
}


For the first problem maybe I can help you with this:

var jsUtil = jsUtil || {};

jsUtil.arraysSame = function(a, b){
    //both must be arrays
    if (!a instanceof Array || !b instanceof Array) {
        return false;
    }
    //both must have the same size
    if (a.length !== b.length) {
        return false;
    }

    var isEquals = true;
    for (var i = 0, j = a.length; i < j; i++) {
        if (a[i] !== b[i]) {

            isEquals = false;
            i = j; //don't use break
        }
    }
    return isEquals;
}

I included type checking and made the things more clear.


In my opinion using built-in predefined functions is always your best bet.

1) Use a function that converts the arrays into strings. There are many of these available and depending on which library you are already using you may want to use different ones. You can find one at Json.org

jsUtil.arraysSame = function(a, b) {

  return JSON.stringify(a) == JSON.stringify(b);
}

2) USe PHP's built in date function and strtotime

class DateUtil {
    function notLeapYear ($var) {
        return (date( 'L', strtotime( $var)) == "0");
    }
}


  • check inputs (type, range - keep in mind that very old dates used a different calendar); you might use PHP date functions to parse date (more flexibility on one hand, limited to relatively recent dates on the other)
  • never iterate with in in javascript, will fail horribly when prototypes of the standard types have been extended
  • you should clarify what the functions should do; e.g. should the array comparison be recursive? Should it use strict equivalence?
  • you can stop iterating the arrays when the first difference is found. Also, you might want to check if the two refer to the same object before starting to iterate.
  • write unit tests
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜