当前位置: 移动技术网 > IT编程>网页制作>CSS > this的四种绑定规则实例讲解

this的四种绑定规则实例讲解

2018年01月24日  | 移动技术网IT编程  | 我要评论

龙木阁,服务行业招聘,hello!

this的四种绑定规则 作为普通函数调用默认绑定 事件处理程序中使用this 严格模式下 作为对象的方法调用隐式绑定 对象属性引用链中只有最顶层影响调用位置 隐式丢失 Functionprototypecall 或 Functionprototypeapply 调用显式绑定 定时器内含有this 硬绑定 API调用的上下文 构造器调用new绑定

this的四种绑定规则

JavaScript 的 this 总是指向一个对象,而具体指向哪个对象是在运行时基于函数的执行环境动态绑定的,而非函数被声明时的环境

1.作为普通函数调用–默认绑定

当函数作为普通函数调用,也就是不作为某个对象的属性调用时,函数中的this指向全局对象window。

window.name = 'globalName'; 
var getName = function(){ 
    return this.name; 
}; 
console.log( getName() );    // globalName 
window.name = 'globalName'; 
var myObject = { 
    name: 'sven', 
    getName: function(){ 
        return this.name; 
    } 
}; 
var getName = myObject.getName;
 //将getName()方法传递给变量getName,此时getName()方法还未执行。
console.log( getName() );    // globalName 当执行的时候,getName()是作为普通函数调用的。函数的执行环节是window对象。
console.log(myObject.getName()); //sven。 执行环境是myObject对象。

事件处理程序中使用this

var btn = document.getElementById("btn");
btn.onclick = function eve(){
    alert(this.id);     //btn
    function callback(){
        alert(this);  
    }
    callback();        //window
}

以上代码,事件处理程序中eve()中的this,指向它的调用者,也就是btn。但是回调函数callback()是在事件处理程序内部执行的,它并没有被任何对象调用,其this指向window。

如果想让callback的this指向btn,可以用一个变量保存对btn的引用:

btn.onclick = function eve(){
    var that = this;
    function callback(){
        alert(that.id);  
    }
    callback();        //btn
}

严格模式下

如果使用严格模式(strict mode),那么全局对象将无法使用默认绑定,因此 this 会绑定到 undefined:

function foo() {  
    "use strict"; 
    console.log( this.a );  
}  
var a = 2; 
foo();  // Uncaught TypeError: Cannot read property 'a' of undefined

2.作为对象的方法调用–隐式绑定

当函数作为对象的方法被调用时,this 指向该对象:

var obj = { 
    a: 1, 
    getA: function(){ 
        alert ( this === obj );    // true 
        alert ( this.a );    //  1 
    } 
}; 
obj.getA(); 
function foo() {  
    console.log( this.a ); 
} 
var obj = {  
    a: 2, 
    foo: foo  
}; 
obj.foo(); // 2  调用foo()时,this指向obj

以上代码,当函数引用有上下文对象时,隐式绑定规则会把函数调用中的 this 绑定到这个上下文对象。调用 foo() 时 this 被绑定到 obj,因此 this.a 和 obj.a 是一样的。

对象属性引用链中只有最顶层影响调用位置。

function foo() {  
    console.log( this.a ); 
} 
var obj2 = {  
    a: 42, 
    foo: foo  
}; 
var obj1 = {  
    a: 2, 
    obj2: obj2  
}; 
obj1.obj2.foo(); // 42   this指向obj2

隐式丢失

一个最常见的 this 绑定问题就是被隐式绑定的函数会丢失绑定对象,也就是说它会应用默认绑定,从而把 this 绑定到全局对象或者 undefined 上(严格模式)。

var a = "oops, global"; // a 是全局对象的属性 
function foo() {  
    console.log( this.a ); 
} 
var obj = {  
    a: 2, 
    foo: foo  
}; 
var bar = obj.foo; // 函数别名!  
bar();     // "oops, global"
var bar = obj.foo;
相当于:
var bar = function{  
    console.log( this.a ); 
} 
//将obj的foo属性传递给变量bar,此时foo()函数并没有执行,执行将函数体给到变量bar。

以上代码,虽然 bar 是 obj.foo 的一个引用,但是实际上,它引用的是 foo 函数本身,因此此时的bar() 其实是一个不带任何修饰的函数调用,应用了默认绑定。

3.Function.prototype.call 或 Function.prototype.apply 调用–显式绑定

隐式绑定时,必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把 this 间接(隐式)绑定到这个对象上。
  如果不想在对象内部包含函数引用,而想在某个对象上强制调用函数,可以使用call()和apply()方法。它们会把这个对象绑定到this,接着在调用函数时指定这个 this。这种方式称为显示绑定。

var obj1 = { 
    name: 'sven', 
    getName: function(){ 
        return this.name; 
    } 
}; 
var obj2 = { 
    name: 'anne' 
}; 

console.log( obj1.getName() );     //  sven 
console.log( obj1.getName.call( obj2 ) );    //anne ,call()方法改变this指向,使getName中的this指向obj2.
function foo() {  
    console.log( this.a ); 
} 
var obj = {a:2}; 
foo.call( obj ); // 2
// 通过 foo.call(),在调用 foo 时强制把它的 this 绑定到 obj 上。

定时器内含有this

function foo() {
    setTimeout(function(){
        console.log( this.a ); 
    },3000) 
} 
var a = 3;
var obj = { a:2}; 
foo.call( obj ); // 3

以上代码中call()无法改变this的指向。3s后才调用定时器,但是定时器是window对象的方法,所以this还是指向定时器的调用者window。

解决方式1:

function foo() {
    var that = obj;
    setTimeout(function(){
        console.log( that.a ); 
    },3000) 
} 
var a = 3;
var obj = {a:2}; 
foo(); // 2

解决方式2:

function foo() {
    setTimeout(function(){
        console.log( this.a ); 
    }.bind(obj),3000) 
} 
var a = 3;
var obj = {a:2}; 
foo(); // 2

解决方式3:

function foo() {
    setTimeout(() =>{
        console.log( this.a ); 
    },3000) 
} 
var a = 3;
var obj = {a:2}; 
foo.call(obj); // 2

硬绑定

function foo() {  
    console.log( this.a ); 
} 
var obj = {  a:2 }; 
var bar = function() { 
    foo.call( obj ); 
}; 
bar(); // 2 
var bar = function() { 
    foo.call( obj ); 
}; 
相当于:
var bar = function{  
console.log( obj.a ); 
} 
//使用call()方法时,foo内部的this就已经执行了obj。

ES5中提供了内置的bind()方法来实现硬绑定,

bind(..) 会返回一个硬编码的新函数,它会把参数设置为 this 的上下文。

function foo() {  
    console.log( this.a ); 
} 
var obj = {  a:2 }; 
var bar = foo.bind( obj ); 

bar(); // 2

API调用的上下文

JavaScript 语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被称为“上下文”(context),其作用和 bind(..) 一样,确保回调函数使用指定的 this。

function foo(el) {  
    console.log( el, this.id ); 
} 
var obj = { id: "awesome" }; 
[1, 2, 3].forEach( foo, obj );   // 调用 foo(..) 时把 this 绑定到 obj 
// 1 awesome 2 awesome 3 awesome

这些函数实际上就是通过 call(..) 或者 apply(..) 实现了显式绑定。

4.构造器调用–new绑定

function foo(a) {  
    this.a = a; 
}  
var bar = new foo(2); 
console.log( bar.a ); // 2

以上代码,使用 new 来调用 foo(..) 时,会构造一个新对象并把它绑定到 foo(..) 调用中的 this上。

var MyClass = function(){ 
    this.name = 'sven'; 
}; 
var obj = new MyClass(); 
alert ( obj.name );     // sven 

如果构造函数返回了一个引用类型的值,最终的运算结果就会返回这个值:

var MyClass = function(){ 
    this.name = 'sven'; 
    return {    // 显式地返回一个对象 
        name: 'anne' 
    } 
}; 
var obj = new MyClass(); 
alert ( obj.name );     //:anne 

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网