面试题目
这是 搜狐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")方式的赋值”问题,如果各位朋友有新的方案,请不吝指点。也欢迎对我的方案拍砖论讨。

