概念回顾
闭包(Closures) : 任何一个内部函数始终能使用其外部函数定义的参数和变量,即便这个外部函数已经成功返回结束。
回调(Callback) : 回调函数就是一个参数(函数指针),将这个函数指针作为参数传到另一个函数里面,而只有当这个函数执行时才会执行传进去的这个函数。这个过程就叫做回调。如同一个异步过程,而这个Callback可以理解为Call it later。
立即执行函数表达式(IIFE) : 立即执行函数表达式顾名思义,即该函数立即执行,执行完成后自动销毁。其好处是作用域的隔离,即被立即执行函数表达式所包裹的变量和方法不会和立即执行函数表达式外面的变量和方法有任何命名冲突,这样可以把代码很好的封装起来,方便复用。
代码实现
/*
* 功能描述:
* 一个简单的提问和回答程序,并且根据回答情况进行计分,
* 正确得一分,错误不得分。问题会随机抽取,并且使用prompt
* 来提交问题答案的番号,答案提交后立即得到当前问题结果和得分累计情况
* 然后紧接着回答下一道问题。当在prompt中输入"退出"后,程序结束。
*
*/
/**
* 整块代码被IIFE包裹,与外部作用域隔离
*/
(function(){
var Question = function(qContent, answers, rightAnswerIdx){
this.qContent = qContent;
this.answers = answers;
this.rightAnswerIdx = rightAnswerIdx;
};
Question.prototype.display = function(){
console.log(this.qContent);
for(var i=0; i<this.answers.length; i++){
console.log(i + '.' + this.answers[i]);
}
};
Question.prototype.displayScore = function(score){
console.log('当前分数:' + score);
console.log('-----------------');
};
/**
* 这里用到了回调函数这个概念,checkAnswer方法的第二个形参
* callback是为了传入score方法返回的匿名函数。这里定义的sc
* 变量是为了保存回调函数的返回值。
*/
Question.prototype.checkAnswer = function(answer, callback){
var sc;
if(answer === this.rightAnswerIdx){
console.log("正确!");
sc = callback(true);
}else{
console.log("错误!");
sc = callback(false);
}
this.displayScore(sc);
}
/**
* 这里score()方法用到了闭包的概念,因为score()方法会返回
* 另外一个匿名方法,而这个匿名方法会用到score()方法里定义
* 的变量sc,而即便score()函数成功的返回这个匿名方法后,这
* 个匿名方法任然能够使用sc变量。
*/
function score(){
var sc = 0;
return function(correct){
if(correct){
sc++;
}
return sc;
}
}
var holdScore = score();
/**
* 用构造方法创建三个问题对象
*/
var Q1 = new Question('你的名字叫什么?', ['张三', '李四', '王麻子'], 0);
var Q2 = new Question('你的性别是什么?', ['男', '女', '不男不女'], 1);
var Q3 = new Question('你的梦想是什么?', ['成为火影', '成为海贼王的男人', '成为汪峰'], 2);
var QList = [Q1, Q2, Q3];
/**
* 这里使用了递归的方法来重复提问,并且只有当输入
* '退出'时,程序才会结束
*/
function nextQuestion(){
var randomNum = Math.floor(Math.random()*QList.length);
QList[randomNum].display();
var answer = prompt('请输入正确答案:');
if(answer !== '退出'){
QList[randomNum].checkAnswer(parseInt(answer), holdScore);
nextQuestion()
}
}
nextQuestion();
})();