今天中午的时候,舍友发来一道javascript题目给我看,要求调用下面的函数,输出“Yay!!”
function test(arr) {
var random_value = "ac1a39300ce7ee8b6cff8021fd7b0b5caf5bc1c316697bd8f22e00f9fab710d6b8dba23ca80f6d80ca697e7aa26fd5f6";
var check = "20150303";
if((arr === null || arr === undefined)) {
console.log("arr is null or undefined.");
return;
}
if(!arr.hasOwnProperty('length')) {
console.log("length property is null or undefined.");
return;
}
if(arr.length >= 0) {
console.log("i think you're not geek. From now on, a GEEK Only!");
return;
}
if(Object.getPrototypeOf(arr) !== Array.prototype) {
console.log("Oh.... can you give me an array?");
return;
}
var length = check.length;
for(var i=0;i<length;i++) {
arr[i] = random_value[Math.floor(Math.random() * random_value.length)];
}
for(i=0;i<length;i++) {
if(arr[i] !== check[i]) {
console.log("Umm... i think 2015/03/03 is so special day.\nso you must set random value to 20150303 :)");
return;
}
}
console.log("Yay!!");
}
粗略看了一下题目,尝试了下
var arr=[];
test(arr);//i think you're not geek. From now on, a GEEK Only!
输出了i think you’re not geek. From now on, a GEEK Only! 赤裸裸地被作者鄙视了呀。可见,在第三个判断if(arr.length >= 0)
这里就过不去了。一般来说,数组的length属性都不能小于0的。强制给arr.length赋值会怎么样呢
arr.length=-1;
//Uncaught RangeError: Invalid array length
果然抛出了错误,看来这个思路不行。换条路走
自己定义一个对象试试吧
var arr={length:-1};
test(arr);//Oh.... can you give me an array?
第三个判断是过去了,第四个if(Object.getPrototypeOf(arr) !== Array.prototype)
没过去呢,要求是数组哦。可是数组的length属性又不能小于0。这下子好像出现了死循环。然后我谷歌了一下Object.getPrototypeOf()
官方定义:The Object.getPrototypeOf() method returns the prototype (i.e. the value of the internal [[Prototype]] property) of the specified object.
var proto = {};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true
简单的说,就是返回对象的prototype属性
于是我就想,那就让arr的prototype指向Array.prototype呀。试试
var arr={length:-1};
arr.prototype=Array.prototype;
test(arr);
//Oh.... can you give me an array?
还是不行,第四关还是过不了,我自己输出Object.getPrototypeOf(arr)和Array.prototype看看,结果为
Object.getPrototypeOf(arr)
//Object {}
Array.prototype
//[]
用{}这样形式生成的还是object对象,不是数组对象。怎么办,换个思路。于是想到另一种生成对象的方式
var MyArr=function(){
this.length=-1;
}
MyArr.prototype=Array.prototype;
var arr=new MyArr();
test(arr);//Umm... i think 2015/03/03 is so special day.
//so you must set random value to 20150303 :)
太棒了,第四关过了,nice。好兴奋,胜利就在眼前。这种方式构造出来的对象,使用的是Array.prototype的原型链。相当于new Array(),但是constructor用的是我们MyArr自己定义的。(这里我的理解解释不知道是不是正确,如果有误,欢迎指出修改)
接下来第五关
var random_value = "ac1a39300ce7ee8b6cff8021fd7b0b5caf5bc1c316697bd8f22e00f9fab710d6b8dba23ca80f6d80ca697e7aa26fd5f6";
var check = "20150303";
var length = check.length;
for(var i=0;i<length;i++) {
arr[i] = random_value[Math.floor(Math.random() * random_value.length)];
}
for(i=0;i<length;i++) {
if(arr[i] !== check[i]) {
console.log("Umm... i think 2015/03/03 is so special day.\nso you must set random value to 20150303 :)");
return;
}
}
出题者要求arr数组的内容是“20150303”。然后函数中又给arr赋值,而且赋的是随机值。我一看,出题者使的一定是个障眼法,让我们去纠结那些随机数怎么搞出”20150303”。我们不能在这里花时间,得换个思路。想了想,有没有一种方法,可以让对象的值不能被修改,这样我们在函数外赋值好后,传入函数中,就不会被修改了。这个思路似乎可行,立马谷歌。
找到了Object.freeze();这个方法。我们来看一下官方定义
概述EDIT
Object.freeze() 方法可以冻结一个对象。冻结对象是指那些不能添加新的属性,不能修改已有属性的值,不能删除已有属性,以及不能修改已有属性的可枚举性、可配置性、可写性的对象。也就是说,这个对象永远是不可变的。该方法返回被冻结的对象。语法EDIT Object.freeze(obj)
这样问题似乎都解决了,试试
var MyArr=function(){
this.length=-1;
}
MyArr.prototype=Array.prototype
var arr=new MyArr()
arr[0]='2';
arr[1]='0';
arr[2]='1';
arr[3]='5';
arr[4]='0';
arr[5]='3';
arr[6]='0';
arr[7]='3';
Object.freeze(arr);
test(arr);//Yay!!
终于,功夫不负有心人,问题解决了。在这个猜测、验证、搜索和思考过程中,得到了很多锻炼。每解决一步都给人成就感。感谢我舍友给我发来这一道题。