arguments.callee
1、arguments
首先f12跑一下函数:
function myfun(){
console.log(arguments);
}
myfun(1,2,3,4,5);
结果如下截图:
可以看出argumetns好像是数组,又不是数组,因为[]中又包含了其他的东西;
展开可得:
可以看出,arguments其实是一个对象,它与数组一样有索引以及length的属性。但是却不能使用数组的方法。但是在实际开发中,我们可以使用arguments获取到所有的实参,同时也需要对其使用写数组的方法。
arguments对象转化为数组的方法:
(1)借用数组的slice方法
Array.prototype.slice.APPly(arguments);
Array.prototype.slice.call(arguments);
//以上调用Array对象原型中的方法,所以需要prototype
//而以下写法中[]是一个Array的实例,所以不需要prototype
[].slice().apply(arguments);
PS:为什么要加上apply或call()?
apply和call方法接受的第一个参数便是指定的作用域,接受arguments作为第一个参数说明Array.prototype.slice将在特定作用域argumnts中去调用slice方法。
(2)借用数组的concat方法
thisArg是新的空数组,apply方法将函数this指向thisArg,arguments做为类数组传参给apply。根据apply的方法的作用,即将Array.prototype.concat方法在指定的this为thisArg内调用,并将参数传给它。
Array.prototype.concat.apply(thisArg,arguments);
(3)使用es6的扩展运算符
...arguments;
2、arguments.callee()
callee 是 arguments 对象的一个属性。它可以用于引用该函数的函数体内当前正在执行的函数。这在函数的名称是未知时很有用,例如在没有名称的函数表达式 (也称为“匿名函数”)内。
在严格模式下,ES5禁止使用 arguments.callee() 。当一个函数必须调用自身的时候, 避免使用 arguments.callee(), 则要么需要给函数表达式一个名字,要么使用一个函数声明。
function factorial (n) {
return !(n > 1) "prism language-javascript">function testCaller(){
var caller = testCaller.caller; //被调用函数才有的caller属性
console.log(caller);
}
function aCaller() {
testCaller(); //被调用
}
aCaller();
结果如下:
call,apply,bind都是用来重新定义this指向的。
普通函数调用,this都是指向window的。
settimeout是一个回调函数,它的this指的是window。
4、call()
call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。
var arr = [1, 2, 3, 89, 46]
var max = Math.max.call(null, arr[0], arr[1], arr[2], arr[3], arr[4]);
//89
var obj = {
message: 'My name is: '
}
function getName(firstName, lastName) {
console.log(this.message + firstName + ' ' + lastName)
}
//getName中的this指向obj,后面传入参数列表
getName.call(obj, 'pengpeng', 'maizi');
//My name is: pengpeng maizi
5、apply()
apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。
var arr = [1,2,3,89,46]
var max = Math.max.apply(null,arr)//89
var obj = {
message: 'My name is: '
}
function getName(firstName, lastName) {
console.log(this.message + firstName + ' ' + lastName)
}
//getName中的this指的是obj,第二个参数传入的是数组
getName.apply(obj, ['pengpeng', 'maizi'])
// My name is: pengpegn maizi
call和apply可用来借用别的对象的方法,这里以call()为例,apply同理:
var Person1 = function () {
this.name = 'pengpeng qimai';
}
var Person2 = function () {
this.getname = function () {
console.log(this.name);
}
Person1.call(this); //即Person2里边的this指的是Person1
}
var person = new Person2();
person.getname();
//pengpeng qimai
6、bind()
和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。
var obj = {
name: 'pengpeng qimai'
}
function printName() {
console.log(this.name)
}
var dot = printName.bind(obj) ;
//会返回一个新的函数,而原函数不会被改变
console.log(dot) ;
dot() // pengpeng qimai
bind 方法不会立即执行,而是返回一个改变了上下文 this 后的函数。而原函数 printName 中的 this 并没有被改变,依旧指向全局对象 window。
function fn(a, b, c) {
console.log(a, b, c);
}
var fn1 = fn.bind(null, 'pengpengqimai');
fn('A', 'B', 'C'); // A B C
fn1('A', 'B', 'C'); // pengpengqimai A B
fn1('B', 'C'); // pengpengqimai B C
fn.call(null, 'pengpengqimai');
// pengpengqimai undefined undefined
call 是把第二个及以后的参数作为 fn 方法的实参传进去,而 fn1 方法的实参实则是在 bind 中参数的基础上再往后排。
7、应用场景
(1)求数组中的最大和最小值
var arr = [1,2,3,89,46]
var max = Math.max.apply(null,arr)//89
var min = Math.min.apply(null,arr)//1
(2)将类数组转化为数组
var trueArr = Array.prototype.slice.call(arrayLike)
(3)数组追加
var arr1 = [1,2,3];
var arr2 = [4,5,6];
var total = [].push.apply(arr1, arr2);//6
// arr1 [1, 2, 3, 4, 5, 6]
// arr2 [4,5,6]
(4)判断变量类型
function isArray(obj){
return Object.prototype.toString.call(obj) == '[object Array]';
}
isArray([]) // true
isArray('pengpengqimai') // false
(5)利用call和apply做继承
function Person(name,age){
// 这里的this都指向实例
this.name = name
this.age = age
this.sayAge = function(){
console.log(this.age)
}
}
function Female(){
Person.apply(this,arguments)//将父元素所有方法在这里执行一遍就继承了
}
var dot = new Female('pengpengqimai',2);
(6)使用 log 代理 console.log
function log(){
console.log.apply(console, arguments);
}
// 当然也有更方便的 var log = console.log()
8、总结
call、apply和bind函数存在的区别:
- bind返回对应函数, 便于稍后调用; apply, call则是立即调用。 除此外,
- 在 ES6 的箭头函数下, call 和 apply 将失效, 对于箭头函数来说:
(1)箭头函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象;所以不需要类似于var _this = this这种丑陋的写法
(2)箭头函数不可以当作构造函数,也就是说不可以使用 new 命令, 否则会抛出一个错误
(3)箭头函数不可以使用 arguments 对象,,该对象在函数体内不存在. 如果要用, 可以用 Rest 参数代替
(4)不可以使用 yield 命令, 因此箭头函数不能用作 Generator 函数,什么是Generator函数可自行查阅资料,推荐阅读阮一峰Generator 函数的含义与用法,Generator 函数的异步应用
参考文章:https://www.jianshu.com/p/bc541afad6ee(原文写的更加详细,想深入了解的小伙伴可以戳进去研究一下~)
相关阅读
arguments 的主要用途是保存函数参数, 但这个对象还有一个名叫 callee 的属性,返回正被执行的 Function 对象,也就是所指定的 Functi
https://www.cnblogs.com/lmy2016/p/6087872.html argument为函数内部对象,包含传入函数的所有参数, arguments.callee代表函数名,多
extjs的apply,applyIf和merge用法及原理剖析
extjs的apply,applyIf和merge都用来操作2个对象并生成新对象,在实现结果上是有区别的,下面来看下他们的区别:先定义2个对象:var obj1
arguments.callee 属性包含当前正在执行的函数。描述callee 是 arguments 对象的一个属性。它可以用于引用该函数的函数体内
转载网址:http://www.cnblogs.com/yin-jingyu/archive/2011/07/30/2122176.htmlapply的用法:Ext中apply及applyIf方法的应用apply及