在ECMAscript标准标准中定义了call()和apply()两种方法,能够改变函数的上下文,也就是函数内部this的指向
-
call()
call: 英 [kɔːl] 美 [kɔl]
- vi. 呼叫;拜访;叫牌
- vt. 呼叫;称呼;召集
- n. 电话;呼叫;要求;访问
Function.call(obj , arg1, arg2, ...)
obj:这个对象将代替Function类里this对象
params:这个是一个参数列表
-
apply()
apply英 [ə'plaɪ] 美 [ə'plaɪ]
- vt. 申请;涂,敷;应用
- vi. 申请;涂,敷;适用;请求
Function.apply(obj,args)
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args-->arguments)
-
相同点
call()和apply()都能通过点语法的调用方式,来指定上下文执行这个函数
例子:
function test() {
console.log(this.name);
}
var obj = {
name: '小明',
age: 12
};
test.call(obj);
test.apply(obj);
控制台输出结果为:
小明
小明
-
不同点
call()和apply()唯一的区别就是接受的参数不一样,call的参数形式是一个参数列表,apply的参数是一个数组
例子:
function test(a,b,c) {
console.log(a+b+c);
console.log(this.name);
}
var obj = {
name: '小明',
age: 12
};
test.call(obj,1,2,3);
test.apply(obj,[1,2,3]);
控制台输出结果为:
6
小明
6
小明
-
严格模式和非严格模式
在非严格模式下,第一个参数传递为null或者undefined时,函数内的this会指向默认的宿主对象,在浏览器中是window
例子:
var test=function(){
console.log(this===window);
}
test.apply(null);
test.call(undefined);
控制台输出结果为:
true
true
-
关于继承
例子:
function Animal(name){
this.name = name;
this.showName = function(){
console.log(this.name);
}
}
function Cat(name){
Animal.call(this, name);
}
var cat = new Cat("Black Cat");
cat.showName();
控制台输出结果为:
Black Cat
-
解决this被随意更改的问题
在实际开发中,经常会遇到this指向被不经意改变的场景。
有一个局部的fun方法,fun被作为普通函数调用时,fun内部的this指向了window,但我们往往是想让它指向该#test节点。
例子:
window.id="window";
document.querySelector('#test').onclick = function(){
console.log(this.id);
var fun = function(){
console.log(this.id);
}
fun();
}
控制台输出结果为:
test
window
解决:
window.id="window";
document.querySelector('#test').onclick = function(){
console.log(this.id);
var fun = function(){
console.log(this.id);
}
fun.call(this);
}
控制台输出结果为:
test
test
也可以这样做,不过在ECMAScript 5的strict模式下,这种情况下的this已经被规定为不会指向全局对象,而是undefined
例子:
window.id="window";
document.querySelector('#test').onclick = function(){
var that = this;
console.log(this.id);
var fun = function(){
console.log(that.id);
}
fun();
}
function func(){
"use strict"
alert ( this ); // undefined
}
func();
控制台输出结果为:
test
test
-
其他用法
-
类数组
这里把符合以下条件的对象称为类数组
-
具有length属性
-
按索引方式存储数据
-
不具有数组的push,pop等方法
常见类数组有 arguments,NodeList!
(function(){
Array.prototype.push.call(arguments,4);
console.log(arguments);
})(1,2,3)
控制台输出结果为:
[1, 2, 3, 4]
这样就往arguments中push一个4进去了
-
Array.prototype.push 页可以实现两个数组合并
同样push方法没有提供push一个数组,但是它提供了push(param1,param,…paramN) 所以同样也可以通过apply来装换一下这个数组,即:
var arr1=new Array("1","2","3");
var arr2=new Array("4","5","6");
Array.prototype.push.apply(arr1,arr2);
console.log(arr1);
控制台输出结果为:
["1", "2", "3", "4", "5", "6"]
也可以这样理解,arr1调用了push方法,参数是通过apply将数组装换为参数列表的集合.
-
求类数组中的最大值
(function(){
var maxNum = Math.max.apply(null,arguments);
console.log(maxNum);
})(34,2,56);
控制台输出结果为:
56
-
判断类型
console.log(Object.prototype.toString.call(123))
console.log(Object.prototype.toString.call('123'))
console.log(Object.prototype.toString.call(undefined))
console.log(Object.prototype.toString.call(true))
console.log(Object.prototype.toString.call({}))
console.log(Object.prototype.toString.call([]))
console.log(Object.prototype.toString.call(function(){}))
控制台输出结果为:
[object Number]
[object String]
[object Undefined]
[object Boolean]
[object Object]
[object Array]
[object Function]
注:文章内容参考网络,后整理。
网友评论