重构JavaScript和PHP代码[求职面试]

时间:2010-10-28 15:36:49

标签: php javascript refactoring

最近我接受了面试。我有两个任务:

1)重构JavaScript代码

// 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)重构检查闰年的PHP函数

<?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' : 'falls') ?> in a leap year</li>
  <? } ?>
</ul>

我认为我应对这项任务,但我不太确定,我仍然没有得到他们的答复,而且已经过了一个星期。你能举例说明你对这项任务的态度吗?我真的很感激。稍后我可以发布我的解决方案/代码。

好的,这是我对问题的回答。

<?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);

5 个答案:

答案 0 :(得分:5)

使用for循环而不是for...in迭代数组。如果数组不同,您希望尽快返回,因此从长度比较开始并立即返回您遇到两个数组之间不同的元素。使用严格不等运算符!==比较它们。向后遍历数组以获得速度,并通过将a的长度分配给i并重用i作为迭代变量来最小化所需的变量数。

此代码假定参数ab都已提供,并且都是Array个对象。这似乎暗示了这个问题。

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;
};

答案 1 :(得分:3)

对于PHP版本:

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)) {
    }
}

答案 2 :(得分:1)

对于第一个问题,我可以帮助你:

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;
}

我包含了类型检查并使事情变得更加清晰。

答案 3 :(得分:0)

在我看来,使用内置的预定义功能总是最好的选择。

1)使用将数组转换为字符串的函数。有许多这些可用,根据您已经使用的库,您可能想要使用不同的库。您可以在Json.org

找到一个
jsUtil.arraysSame = function(a, b) {

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

2)使用PHP的内置日期函数和strtotime

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

答案 4 :(得分:0)

  • 检查输入(类型,范围 - 请记住,非常旧的日期使用不同的日历);您可以使用PHP日期函数来解析日期(一方面更灵活,另一方面仅限于相对较新的日期)
  • 永远不会在javascript中使用in进行迭代,在扩展标准类型的原型时会非常失败
  • 你应该澄清这些功能应该做什么;例如数组比较应该是递归的吗?它应该使用严格的等价吗?
  • 您可以在找到第一个差异时停止迭代数组。此外,您可能想要在开始迭代之前检查两者是否引用相同的对象。
  • 写单元测试