this对象以及call、apply、bind方法

在现在前端面试中,最喜欢考的两点,第一,原型和原型链;第二,作用域和闭包。在作用域这一块,this对象一般都是必问的环节。JS所有的函数作用域内都有一个this对象代表该函数的对象。在全局作用域中,this代表全局对象。当一个函数作为对象的方法调用时,默认的this的值等于那个对象。

1.也就是说,谁调用这个方法,this就指向谁。请看下面一个例子

 

var  name = "Tom";
function sayNameAll(){
      console.log(this.name);
}
var person = {
     name:"xiaoming",
     sayName:sayNameAll
};
person.sayName(); //outputs "xiaoming"
sayNameAll();  //outputs "Tom"

在上面的例子中,我们发现一个现象,在普通函数中,this指向window对象,所以我们调用sayNameAll方法,输出的是全局变量Tom。

2.构造函数中this指向实例化的对象,而普通函数中this指向的window对象

var name = "博客园";
function frintName(){
    var name = "网易";
    console.log(this.name);
}
frintName(); //outputs "博客园"

function Frint(){
    this.name = "GitHub";
    this.frint = function(){
        console.log(this.name);
    }
}
var obj = new Frint();
obj.frint();  //outputs"GitHub"

3.定时器中的this指向的是window对象。因为setTimeout和setInterval这两个方法,是window的方法,只能window才能调用,所以这两个方法中,this都是指向window。

var name = "博客园";
function Frint(){
    this.name = "GitHub";
    this.frint1 = function(){
        console.log(this.name);
    }
    this.frint2 = function(){
        setTimeout(this.frint1,1000);
    }
}
var obj = new Frint();

obj.setTimeout(function(){
    console.log(100);
},100); //Uncaught TypeError: obj.setTimeout is not a function
    at <anonymous>,报错,只能window调用,当然也可以借用call等方法
obj.frint1(); //outputs"GitHub"
obj.frint2(); //outputs"博客园",定时器中this指向window对象

4.一般this会被自动设置,但是我们也可以改变它的指向来完成不同的任务。有三种函数方法来改变this,这就是call,apply,bind。

先看call方法

var name = "博客园";
function frintName(){
    console.log(this.name);
}
var name1 = {
    name:'Github'
}
var name2 = {
    name:'Html5'
}
frintName.call(this); //outputs "博客园",这里的this不写也可以,默认指向window
frintName.call(name1); //outputs"Github"
frintName.call(name2); //outputs"Html5"

由于我们显示的指定了this的值,而不是让js引擎自动指定,所有结果发生改变。

apply方法和call方法几乎一样,只是apply只接受两个参数,第一个参数是this的值,第二个是类数组对象,里面是要被传入函数的参数。而call方法中,参数一列排开。如果传入的参数很多,且是一个数组,那建议用apply,如果只是一个变量,那么用call方法

var name = "博客园";
function frintName(url1,url2){
    console.log(url1+url2+this.name);
}
var name1 = {
    name:'Github'
}

frintName("web1","web2"); //outputs "web1web2博客园"
frintName.call(name1,'web1',"web2"); //outputs "web1web2Github"
frintName.apply(name1,['web1','web2']); 
 //outputs"web1web2Github"

5.bind方法。

bind方法是ES5中增加的,所以它的用法和call、apply有一点区别。同样,他的第一个参数是传给this的值。

function frintName(url1){
    console.log(url1+this.name);
}
var name1 = {
    name:'Github'
}
var name2 = {
    name:'Html5'
}
var nameFrint1 = frintName.bind(name1);
nameFrint1('web1'); //outputs"web1Github"
var nameFrint2 = frintName.bind(name2,'web2');
nameFrint2();  //outputs"web2Html5"
name2.sayName = nameFrint1;
name2.sayName('web2');//outputs"web2Github"

在上面倒数第二行,我们将nameFrint1设置为name2的sayName的方法,按照惯例,它应该输出name2 中的name值,可是我们发现,竟然输出了name1中的值,为何,他的this值已经绑定。所以,即使现在他是name2的方法,但是依然输出name1中的值。

 

posted @ 2018-01-10 14:29  朱虚  阅读(182)  评论(0编辑  收藏  举报