JavaScript语法——this

Posted emptylee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript语法——this相关的知识,希望对你有一定的参考价值。

这里总结js中一个重点——this。
 
js中函数的this,并不是指向函数本身或者某个作用域,而是指向对象。简单地说,哪个对象调用该函数,则该函数里的this就指向这个对象。但实际写代码时会遇到更复杂的情况。
 
this的复杂,原因是它取决于函数在代码中被调用的位置而不是声明的位置,也就是说this并不遵循词法作用域,而是要看运行时的上下文。
 
this的绑定规则主要有4种。当然,还会有个别特例。但是只要能理解这几种绑定规则,写出具有this风格的代码便不是问题。
 
1 默认绑定。如果函数是独立调用,即直接使用不带任何修饰的函数引用进行调用的,那么就是默认绑定。默认绑定下,如果使用非严格模式,this会绑定全局对象,浏览器中是window对象。如果使用严格模式(strict mode),则全局对象讲无法使用默认绑定,则this会绑定到undefined。
 
例:
//非严格模式
function foo() {
    console.log( this.a );
}
var a = 2;
foo(); // 2
 
//严格模式
function foo() {
    "use strict";
    console.log( this.a );
}
var a = 2;
foo(); // TypeError: this is undefined
 
2 隐式绑定。当一个函数被当做引用属性添加到一个对象obj中或者这个函数(方法)本身就是在obj中定义,当函数的调用是通过obj对象的属性的形式调用时,函数调用中的this会被绑定到obj对象。注意,对象属性引用链中只有最后一层会影响调用位置。
 
例:
function foo() {
    console.log( this.a );
}
var obj2 = {
    a: 2,
    foo: foo
};
var obj1 = {
    a: 1,
    obj2: obj2
};
obj1.obj2.foo(); // 2
 
即,只用管直接调用函数的那个对象,this就是绑定在这个对象上的。
 
隐式绑定有两个情况会导致隐式丢失,即this没有绑定在相应的绑定对象上,而是会采用默认绑定,即绑定到全局对象或undefined上。这两种情况是:
 
一 将函数赋值给变量
 
function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
var bar = obj.foo; // 函数别名!
var a = "oops, global"; // a 是全局对象的属性
bar(); // "oops, global"
 
上面的代码中,bar引用的是函数foo本身。即var bar = obj.foo 是把等号右边的结果赋给等号左边的变量,本质上调用的是返回的函数本身,所以最后函数的调用是不带任何修饰的函数调用,this为默认绑定。
 
有一种情况要注意识别:
function foo() {
    console.log( this.a );
}
var a = 2;
var o = { a: 3, foo: foo };
var p = { a: 4 };
o.foo(); // 3
(p.foo = o.foo)(); // 2
 
(p.foo = o.foo)(),这样的直接调用,实际上是调用等号右边的返回值,即foo,所以结果是2。
如果是p.foo = o.foo;p.foo(),则返回4,相当于分两步,最后调用的是p的foo方法。
 
二 函数作为参数传递
 
function foo() {
    console.log( this.a );
}
var obj = {
    a: 2,
    foo: foo
};
var a = "oops, global"; // a 是全局对象的属性
setTimeout( obj.foo, 100 ); // "oops, global"
 
上面这段代码中,obj.foo被当做回调函数传入定时器函数。这里面相当于是一次赋值。所以函数调用后,里面的this是默认绑定。
 
setTimeout() 函数实现和下面的伪代码类似:
function setTimeout(fn,delay) {
    // 等待 delay 毫秒
    fn(); // <-- 调用位置!
}
 
 
 
3 显式绑定
使用call,apply,bind这三个函数中的任意一个来讲函数的this绑定到指定的对象。
call和apply的用法相同,唯一不同的就是参数传递,apply函数的参数接受的是数组。(这也是apply函数的一个特殊用法,即遇到需要把数组分成一个个参数的情况时,可以用apply函数,这个函数用法不展开讲了)。
 
function foo(something) {
    console.log( this.a, something );
    return this.a + something;
}
// 简单的辅助绑定函数
function bind(fn, obj) {
    return function() {
        return fn.apply( obj, arguments );
};
}
var obj = {
    a:2
};
var bar = bind( foo, obj );
var b = bar( 3 ); // 2 3
console.log( b ); // 5
 
bind函数将foo函数的this强制绑定在obj对象上。这里还有一点注意,上面的bind是一个简单的辅助绑定函数,但是却能体现bind函数的原理,即bind函数作为一个包装的函数,调用它返回真正处理绑定的函数,所以调用bar函数并传入参数时才将foo函数的绑定在obj。
 
4 new绑定
 
function foo(a) {
    this.a = a;
}
var bar = new foo(2);
console.log( bar.a ); // 2
使用new来进行构造函数调用产生新对象,则这个新对象会绑定到函数调用的this。
 
 
通过以上4种情况可以判断函数在某个调用位置的this指向。上面4中情况的优先级从高到低分别是:
1 new 调用
2 call或者apply(或者bind)调用
3 上下文对象调用,
4 默认调用
即如果在调用位置有两种情况同时发生,this的绑定对象取决于优先级高的一种情况。
 
 
 欢迎互相交流,互相学习。前端开发QQ群:711357426

以上是关于JavaScript语法——this的主要内容,如果未能解决你的问题,请参考以下文章

Javascript的基本语法

JavaScript:基础语法

JavaScript的语法规则

JavaScript基础语法整理

JavaScript学习笔记——JavaScript语法之对象

JavaScript的基础语法