call
JavaScript 的函数存在「定义时上下文」和「运行时上下文」以及「上下文是可以改变的」这样的概念。
有时候某些对象想临时调用别的对象的某种方法,就可以使用call改变方法内部的this指向以此达到使用方法的目的。
与apply的区别,call使用函数所需要的参数需要一个一个列出来,而apply可以提供Array实例或者arguments对象给它
var currObj = {};
function sum(a, b) {
return a + b;
}
currObj.sum(); //显然不可以
sum.call(currObj); //sum实际上是window.sum;this也是指向window的;所以实际上也是调用别的对象的方法
//改成这样呢
function sum(b) {
return a + b;
}
sum.call(currObj, 3); //NaN,显然报错是吧,都不知a为何物嘛
//那么给currObj加上a属性
currObj.a = 123;
sum.call(currObj, 3); //NaN,发现仍然报错,原来call改变的只是显式的this,这里执行查找a时,首先在环境变量对象寻找,没有,然后查找上一层也就是window,也没有,所以报错
//再改
function sum(b) {
return this.a + b; //这样才能找到
}
顺便学习下slice
function c() {
console.log(Object.getOwnPropertyNames(arguments)); //[length, callee],各个浏览器实现一致
console.log(Object.prototype.toString.call(arguments)); // [object arguments]
var args = arguments.slice(1); //会报错,arguments根本就没有这个方法
}
c(1, 2, 3);
function a() {
var slice = [].slice; //slice方法,Array实例对象才有slice方法(Firefox在Array上也实现了它,不过用法有所不同),也可以用Array.prototype.call(arguments, 1)
var args = slice.call(arguments, 1); //本来arguments对象是没有slice方法的,于是通过call强行调用
console.log(args);
}
a(1, 2, 3);
//Firefox里面Array实现了slice函数,接受含有length属性的参数1,和位置参数)
function b() {
var args = Array.slice(arguments, 1, 3);
console.log(args); //[2, 3]
}
b(1, 2, 3, 4)
//如果这样用呢
function b() {
var args = Array.slice.call(arguments, [1, 2, 3, 4], 1, 3); //其实也就是使用arguments调用了Array.slice,但业务上和arguments没有半毛钱关系
console.log(args); // [2, 3]
}
b(); //执行b(6, 5, 3, 2);结果也是一样的,因为根本就不是对arguments切片
apply
和call用法一样,除了传递参数的方式不同
caller
Function.prototype上的属性,所有函数实例都有这个属性
caller返回调用当前正在执行的函数的函数的引用,如果是顶层调用(即没有上层函数调用),则为null,或者函数没有执行时,打印函数的该属性也返回null
var a = function () {
console.log(a.caller);
console.log(a.caller === b);
}
var b = function () {
a();
}
console.log(a.caller); // null
a(); // null; false
b(); // function b; true
callee
callee返回正在执行的函数本身的引用,它是arguments的一个属性,call代码里面有提到
多被用来作递归操作。
var sum = function (n) {
if (n <= 0)
return 1;
else
return n + arguments.callee(n - 1);
}
sum(10);
另外,arguments.callee.length表示函数的形参长度;arguments.length代表实参长度,即真正传进来的参数个数
function num(a, b, c) {
console.log(arguments.length); //5
console.log(arguments.callee.length); //3
}
num(1, 3, 5, 7, 9);