面试题目
这是 搜狐JavaScript面试题 ,要求如下:
实现一个叫Man的类,包含attr, words, say三个方法。
var Man; // +++++++++++答题区域+++++++++++ // +++++++++++答题结束+++++++++++ try { var me = Man({ fullname: "小红" }); var she = new Man({ fullname: "小红" }); console.group(); console.info( "我的名字是:" + me.attr("fullname") + "\n我的性别是:" + me.attr("gender" )); console.groupEnd(); /* ------[执行结果]------ 我的名字是:小红 我的性别是:<用户未输入> ------------------ */ me.attr( "fullname", "小明" ); me.attr( "gender", "男" ); me.fullname = "废柴" ; me.gender = "人妖" ; she.attr( "gender", "女" ); console.group(); console.info( "我的名字是:" + me.attr("fullname") + "\n我的性别是:" + me.attr("gender" )); console.groupEnd(); /* ------[执行结果]------ 我的名字是:小明 我的性别是:男 ------------------ */ console.group(); console.info( "我的名字是:" + she.attr("fullname") + "\n我的性别是:" + she.attr("gender" )); console.groupEnd(); /* ------[执行结果]------ 我的名字是:小红 我的性别是:女 ------------------ */ me.attr({ "words-limit": 3 , "words-emote": "微笑" }); me.words( "我喜欢看视频。" ); me.words( "我们的办公室太漂亮了。" ); me.words( "视频里美女真多!" ); me.words( "我平时都看优酷!" ); console.group(); console.log(me.say()); /* ------[执行结果]------ 小明微笑:"我喜欢看视频。我们的办公室太漂亮了。视频里美女真多!" ------------------ */ me.attr({ "words-limit": 2 , "words-emote": "喊" }); console.log(me.say()); console.groupEnd(); /* ------[执行结果]------ 小明喊:"我喜欢看视频。我们的办公室太漂亮了。" ------------------ */ } catch (e){ console.error( "执行出错,错误信息: " + e); }
分析过程
分析如下:
从实例化对象的方式看,用new或不用都可以,这是一种作用域安全构造函数,原理就是检查this是不是指向当前方法本身,如果不是就强制new一个对象出来。所以大体框架如下:
Man= function (obj){ if ( this instanceof arguments.callee){ for ( var e in obj){ this [e]= obj[e]; } } else { return new Man(obj); } };
通过观察可以发现,attr方法可以获取或设置属性值,并且参数可以是一个字符串,一个字符串加一个值,一个对象。所以attr方法定义如下:
Man.prototype.attr= function (attr,val){ if (val){ this [attr]= val; } else { if ( typeof attr === "string" ){ return this .hasOwnProperty(attr)? this [attr]:"<用户未输入>" ; } else if ( typeof attr === "object" ){ for ( var e in attr){ this [e]= attr[e]; } } else { } } }
通过观察words可以发现,这里就是传入了一些字符串,以便在say方法中调用,所以这里直接给Man添加一个words_limit_arr的数组,用来存放这些字符串,所以words方法实现如下:
Man.prototype.words= function (str){ this .words_limit_arr.push(str); }
最后就是say方法了,通过观察可以发现,say方法就是把fullname属性的值加上limit-emote的值,再加上前words-limit个words_limit_arr项连接成的字符串,所以定义如下:
Man.prototype.say= function (){ return this ["fullname"]+ this ["words-emote"]+":"+"\""+ this .words_limit_arr.slice(0, this ["words-limit"]).join("")+"\"" ; }
整个合起来就是:
var Man= function (obj){ if ( this instanceof arguments.callee){ for ( var e in obj){ this [e]= obj[e]; } this .words_limit_arr= []; } else { return new Man(obj); } }; Man.prototype.attr = function (attr,val){ if (val){ this [attr]= val; } else { if ( typeof attr === "string" ){ return this .hasOwnProperty(attr)? this [attr]:"<用户未输入>" ; } else if ( typeof attr === "object" ){ for ( var e in attr){ this [e]= attr[e]; } } else { } } } Man.prototype.words = function (str){ this .words_limit_arr.push(str); } Man.prototype.say = function (){ return this ["fullname"]+ this ["words-emote"]+":"+"\""+ this .words_limit_arr.slice(0, this ["words-limit"]).join("")+"\"" ; }
但其中有个问题没有解决,就是用me.fullname="xxx"方式的赋值不能改变me.attr("fullname","xxx")方式的赋值。这个问题导致运行效果如下:
这个问题要如何解决呢,我一直没想到,后来参考了别人的代码,那位朋友的思路是让me.attr("fullname","xxx")方式对fullname的赋值跟me.fullname不是同一个属性。
在没想到其他方案之前,我也只好把我的代码修改如下:
var Man= function (obj){ if ( this instanceof arguments.callee){ this .infos= { }; for ( var e in obj){ this .infos[e]= obj[e]; } this .words_limit_arr= []; } else { return new Man(obj); } }; Man.prototype.attr = function (attr,val){ if (val){ this .infos[attr]= val; } else { if ( typeof attr === "string" ){ return this .infos[attr]? this .infos[attr]:"<用户未输入>" ; } else if ( typeof attr === "object" ){ for ( var e in attr){ this .infos[e]= attr[e]; } } else { } } } Man.prototype.words = function (str){ this .words_limit_arr.push(str); } Man.prototype.say = function (){ return this .infos["fullname"]+ this .infos["words-emote"]+":"+"\""+ this .words_limit_arr.slice(0, this .infos["words-limit"]).join("")+"\"" ; }
修改后运行效果如下:
小结
本面试题主要考查了 作用域安全构造函数,instanceof/typeof 的用法,slice的用法,对数组的遍历,对对象成员的遍历等知识点。
关于上面提到的“用me.fullname="xxx"方式的赋值不能改变me.attr("fullname","xxx")方式的赋值”问题,如果各位朋友有新的方案,请不吝指点。也欢迎对我的方案拍砖论讨。