问答
1.apply、call 有什么作用,什么区别?
在学习apply和call之前,先了解this。
this是什么?
- 以下三种情况this指向全局对象window
(1)函数被直接调用时
console.log(this); //window
function fn1(){
console.log(this); //window
}
fn1();
(2)函数嵌套产生的内部函数的this不是其父函数,仍然是全局对象window
function fn0(){
function fn(){
console.log(this); //window
}
fn();
}
fn0();
(3)setTimeout和setInterval这两个方法执行的函数this也是全局对象window
setTimeout(function(){
console.log(this);
}, 200);
- 作为构造函数调用,所谓构造函数,就是通过这个函数生成一个新对象,这时,this就指这个新对象。
function Person(name){
this.name = name;
}
Person.prototype.printName = function(){
console.log(this); //{name: "Byron", printName: function}
console.log(this.name); //Byron
};
var p1 = new Person('Byron');
p1.printName();
- 作为对象方法调用。当作为一个对象的属性时,该函数被称为该对象的方法,在使用这种调用方式时,this 指该对象。
var obj1 = {
name: 'Byron',
fn : function(){
console.log(this);
}
};
obj1.fn(); //{name:"Byron", fn:function}
- DOM对象绑定事件。在事件处理程序中this代表事件源DOM对象(低版本IE有bug,指向了window)
$("ul").on("click","li",function(e){
console.log(this); //点那个li,this就指向哪个li
})
清楚了this之后,再来看call和apply。
call, apply都属于Function.prototype的一个方法,用于设置函数的执行上下文以及参数,当前操作的函数会被直接调用。
1.applay的语法 fn.applyl(context, [param1, param2...])
applay接受两个参数,第一个参数必须是一个对象,也就是希望设置的this对象,第二个参数是一个数组,这个数组里可以有若干个参数。
var obj1={
name:"candy",
sex:"girl",
fn:function(name,age,sex){
this.name=name;
this.sex=sex;
this.age=age;
console.log(this); //此例中this指向call或applay传入的第一个参数
}
}
var obj2={
name:"mary",
sex:"girl",
hobby:"swim"
}
var fn1=obj1.fn.apply(obj1,["hank",20,"boy"]); //{name: "hank", sex: "boy", fn: function, age: 20}
var fn2=obj1.fn.apply(obj2,["hank",20,"boy"]); // {name: "hank", sex: "boy", hobby: "swim", age: 20}
2.call的语法 fn.call(context, param1, param2...)
call和applay唯一的区别就是,call的若干个参数不需要写在一个数组里。
上述例子用call的写法如下,结果一样
var fn3=obj1.fn.call(obj1,"hank",20,"boy"); //{name: "hank", sex: "boy", fn: function, age: 20}
var fn4=obj1.fn.call(obj2,"hank",20,"boy"); // {name: "hank", sex: "boy", hobby: "swim", age: 20}
3.还有一个与call和apply作用类似的是bind
bind,使函数内部的this为传入的第一个参数,当前操作的函数不会被直接调用,而是返回了一个新的函数。
var obj1={
name:"candy",
sex:"girl",
fn:function(){
console.log(this);
}
}
var fn5=obj1.fn.bind(obj1);
var fn6=obj1.fn.bind({name:123});
fn5(); //{name: "candy", sex: "girl", fn: function}
fn6(); //{name: 123}
代码
1. 以下代码输出什么?
var john = {
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func; //此时john这个对象拥有两个属性,一个是firstName:"John",另一个是sayHi:func(),this指向对象john
john.sayHi() ; //John:hi!
2.下面代码输出什么,为什么?
func();
function func() {
alert(this); //window对象,因为函数被直接调用时,this指向window对象
}
3.下面代码输出什么?
function fn0(){
function fn(){
console.log(this);
}
fn();
}
fn0(); //打印window对象, 因为函数被直接调用时,this指向window对象
document.addEventListener('click', function(e){
console.log(this); //#document, 在事件处理程序中this代表事件源DOM对象
setTimeout(function(){
console.log(this); //打印window对象,因为setTimeout和setInterval这两个方法执行的函数this指向全局对象window
}, 200);
}, false);
4.下面代码输出什么,why?
var john = {
firstName: "John"
}
function func() {
console.log( this.firstName )
}
func.call(john) //打印John, 因为call指定了当前函数的执行上下文,也即对象john
5.代码输出?
var john = {
firstName: "John",
surname: "Smith"
}
function func(a, b) {
console.log( this[a] + ' ' + this[b] ) //相当于console.log(john[firstName]+" "+john[surname])
}
func.call(john, 'firstName', 'surname') //打印"John Smith", 因为call指定了当前函数的执行上下文,也即对象john
6.以下代码有什么问题,如何修改
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指$btn,而$btn并没有showMsg()的方法
this.showMsg();
})
},
showMsg: function(){
console.log('hello!');
}
}
修改方法:利用变量存储当前的this值
var module= {
init: function(){
var $cur=$(this);
$cur.bind();
}
bind: function(){
$btn.on('click', function(){
$cur.showMsg();
})
},
showMsg: function(){
console.log('hello!');
}
}
module.init(); //调用
7.下面代码输出什么?
var length = 3;
function fa() {
console.log(this.length);
}
var obj = {
length: 2,
doSome: function (fn) {
console.log(this.length) //obj调用doSome(),this指向obj
fn(); //window对象调用fa()
arguments[0](); //arguments对象调用fa()
}
}
obj.doSome(fa) //2,3 ,1
第一次打印2:obj调用doSome(),this指向obj
第二次打印出3:此时在函数内部调用fa(),this指向window,所以长度为3
第三次打印1:此时是arguments对象在调用,arguments对象的长度有传入的实参确定,此时只传入了一个参数,也就是参数fn,所以长度为1。