1.题目描述:将函数 fn 的执行上下文改为 obj 对象
解析:在js中,函数也是对象,它的上下文是可以改变的,函数内的this也是可以变化的,this是在执行时确定的,不是定义时确定的。函数可以作为一个对象的方法,也可以同时作为另一个对象的方法,可以通过Function.prototype属性上的call()方法、apply()方法和bind()方法改变函数的上下文,函数中的this指向即为call()方法、apply()方法和bind()方法传入的第一个参数。
note:
- call()方法的作用和 apply() 方法类似,区别是call()方法接受的是参数列表,apply()方法接受的是一个参数数组。
- call()方法、apply()方法和bind()方法区别是返回值不同:(1)call、apply将立即执行该函数(2)bind不执行函数,只返回一个可供执行的函数。
fun.call(thisArg, arg1, arg2, ...)
参数说明:
thisArg:
在fun
函数运行时指定的this
值。if(thisArg == undefined|null) this = window,if(thisArg == number|boolean|string) this == new Number()|new Boolean()| new String()
arg1, arg2, ...
指定的参数列表。返回值:使用调用者提供的
this
值和参数调用该函数的返回值。若该方法没有返回值,则返回undefined
。
fn.call(object)的作用:
1.即刻调用这个函数(fn)
2.调用这个函数的时候函数的this指向object对象
func.apply(thisArg, [argsArray])
参数说明:
thisArg
:可选的。在func
函数运行时使用的this
值。请注意,this
可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为null
或undefined
时会自动替换为指向全局对象,原始值会被包装。
argsArray
:可选的。一个数组或者类数组对象,其中的数组元素将作为单独的参数传给func
函数。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。 注意浏览器的兼容性。返回值:调用有指定
this
值和参数的函数的结果。
bind()方法是创建了一个新的函数称为绑定函数(BF),bind()被调用时,bind()第一个参数指定新函数的this,其余参数加上绑定函数运行时本身的参数按照顺序将作为原函数的参数来调用原函数。
function.bind(thisArg[, arg1[, arg2[, ...]]])
参数说明:
thisArg
:调用绑定函数时作为this
参数传递给目标函数的值。 如果使用new
运算符构造绑定函数,则忽略该值。当使用bind
在setTimeout
中创建一个函数(作为回调提供)时,作为thisArg
传递的任何原始值都将转换为object
。如果bind
函数的参数列表为空,执行作用域的this
将被视为新函数的thisArg
。
arg1, arg2, ...
:当目标函数被调用时,预先添加到绑定函数的参数列表中的参数。返回值:返回一个原函数的拷贝,拥有指定的this和初始值。
代码实现:
function speak(fn, obj) {
//实现一:
//return fn.call(obj);
//实现二:
//return fn.apply(obj, []);
//实现三:
return fn.bind(obj)();
}
2.题目描述(使用arguments):函数 useArguments 可以接收 1 个及以上的参数。请实现函数 useArguments,返回所有调用参数相加后的结果。本题的测试参数全部为 Number 类型,不需考虑参数转换。
解析:
代码实现一:
使用arguments对象的特性。arguments能获得传递给函数的参数的类数组对象,其值为一个类数组对象(不是数组),可以通过length获取参数个数,通过下标获取参数位置也可以设置参数,除此之外没有任何Array属性。
function useArguments() {
var sum = 0;
//循环求值
for(var i = 0; i < arguments.length; i++){
sum += arguments[i];
}
return sum;
}
代码实现二:
可以先将arguments数组化,然后使用数组的reduce()方法求和。
function useArguments() {
return Array.prototype.slice.call(arguments).reduce(function(pre, cur){
return pre + cur;
})
}
//简化版:调用reduce方法时调用call方法改变对象,第二个参数即为reduce的回调函数
function useArguments() {
return Array.prototype.reduce.call(arguments,function(pre, cur){
return pre + cur;
})
}
note:如下图所示,将arguments数组化后调用splice方法,此时原数组由[1,2,3,4]变为[1,2,4],再调用slice方法变为[2,4],最后执行reduce方法,结果为2+4=6。
3.题目描述:完成函数 createModule,调用之后满足如下要求:
1、返回一个对象
2、对象的 greeting 属性值等于 str1, name 属性值等于 str2
3、对象存在一个 sayIt 方法,该方法返回的字符串为 greeting属性值 + ', ' + name属性值
实现一:原型模式
function createModule(str1, str2) {
function Obj(){}
Obj.prototype.greeting = str1;
Obj.prototype.name = str2;
Obj.prototype.sayIt = function(){return this.greeting + ", " + this.name;}
return new Obj();
}
实现二:构造函数模式
function createModule(str1, str2) {
function Obj() {
this.greeting = str1;
this.name = str2;
this.sayIt = function(){return this.greeting + ", " + this.name;}
}
return new Obj();
}
实现三:组合使用构造函数模式和原型模式(构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性)
function createModule(str1, str2) {
function Obj(){
this.greeting = str1;
this.name = str2;
}
Obj.prototype.sayIt = function(){return this.greeting + ", " + this.name;}
return new Obj();
}
实现四:工厂模式(创建对象模式)
function createModule(str1, str2) {
function createObj()
{
obj = new Object();
obj.greeting = str1;
obj.name = str2;
obj.sayIt = function(){return this.greeting + ", " + this.name;}
return obj;
}
return createObj();
}
实现五:字面量模式
function createModule(str1, str2) {
return {
greeting: str1,
name: str2,
sayIt: function(){
return this.greeting + ', ' + this.name;
}
};
}
4.题目描述:求 a 和 b 相乘的值,a 和 b 可能是小数,需要注意结果的精度问题
解析:为了确保结果的精度,使用Number的toFixed()方法将结果的小数点位数确定为小数点位数最大的乘数。
代码实现:
function multiply(a, b) {
var str1 = a.toString();
var str2 = b.toString();
var len = Math.max(str1.length - str1.indexOf('.') - 1, str2.length - str2.indexOf('.') - 1);
return parseFloat(a * b).toFixed(len);
}