JavaScript核心技术开发解密--第七章 this
当前函数的this是在函数被调用执行的时候才确定的,简言之,谁调用,this指向谁。
- 默认绑定
首先要介绍的是最常用的函数调用类型:独立函数调用。这是默认的this绑定规则。
function foo () {
console.log(this.a);
}
var a = 2;
foo(); // 2 此时调用foo()默认为全局对象,this.a即是2 以上是非严格模式,如果使用严格模式,那么全局对象将无法使用默认绑定,因此this会绑定到undefined:
function foo () {
"use strict"
console.log(this.a);
}
var a = 2;
foo(); // TypeError: this is undefined 2、隐式绑定
先看一段代码:
function foo () {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2,此时调用foo()的是obj对象,因此this指向obj 对象属性引用链中只有最顶层或者说只有最后一层影响调用位置:
function foo () {
console.log(this.a);
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42 隐式丢失
还是先看一段代码:
function foo () {
console.log(this.a);
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo;
var a = 'oops, global';
bar(); // 'oops, global' 虽然bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar其实是一个不带任何修饰的函数调用,因此应用了默认绑定。
一种更微妙、更常见并且更出乎意料的情况发生在传入回调函数时:
function foo () {
console.log(this.a);
}
function doFoo (fn) {
fn();
}
var obj = {
a: 2,
foo: foo
};
var a = 'oops, global';
doFoo(obj.foo); // 'oops, global' 参数传递其实就是一种隐式赋值,因此我们传入函数时也会被隐式赋值。
JavaScript环境中内置的setTimeout()函数实现和下面的伪代码类似:
function setTimeout (fn, delay) {
// 等待delay毫秒
fn(); // 调用位置
} 3、显示绑定
JavaScript可以使用函数的call和apply方法改变this的指向。它们的第一个参数是一个对象,它们会把这个对象绑定到this,接着在调用函数时指定这个this。因为你可以直接指定this的绑定对象,因此我们称之为显示绑定。
function foo () {
console.log(this.a);
}
var obj = {
a: 2
};
foo.call(obj); // 2,将this指向obj对象 硬绑定
先看一段代码:
function foo () {
console.log(this.a);
}
var obj = {
a: 2
};
var bar = function () {
foo.call(obj);
};
bar(); // 2
setTimeout(bar, 100); // 2
// 硬绑定的bar不可能再修改它的this
bar.call(window); // 2 我们创建了函数bar(),并在它的内部手动调用了foo.call(obj),因此强制把foo的this绑定到了obj。无论之后如何调用函数bar,它总会手动在obj上调用foo,这种绑定是一种显示的强制绑定,因此我们称之为硬绑定。
由于硬绑定是一种非常常用的模式,所以在ES5中提供了内置的Function.prototype.bind,它的用法如下:
function foo (something) {
console.log(this.a, something);
return this.a + something;
}
var obj = {
a: 2
};
var bar = foo.bind(obj);
var b = bar(3); // 2 3
console.log(b); // 5 call、apply和bind都可以改变this指向,主要区别如下:
call:Array.prototype.call(a,1,2,3) apply:Array.prototype.apply(a,[1,2,3])//传参使用数组形式 bind:逐个传入参数值//返回一个函数
4、new绑定
JavaScript有一个new操作符,使用方法看起来和那些面向类的语言一样,然而,JavaScript中new的机制实际上和面向类的语言完全不同。
使用new来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
1.创建(或者说构造)一个全新的对象。
2.这个新对象会被执行[[原型]]连接。
3.这个新对象会绑定到函数调用的this。
4.如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个信息对象。
function foo (a) {
this.a = a;
}
var bar = new foo(2);
console.log(bar.a); // 2 使用new关键字创造对象时,this指向创建的对象。
5、优先级
new绑定>显式绑定/硬绑定>隐式绑定
6、全局对象中的this
全局对象中的this指向自己
this.a = 2;//this此时指向全局对象 //等于 var a = 2;//绑定到全局对象中 //赋值时标识符会隐式绑定到全局对象中 a1=a;
7、函数中的this
在一个函数的执行上下文中,this由该函数的调用者提供,由调用函数的方式来决定。
function fn (){
'use strict' //严格模式下全局对象为undefined
console.log(this)
}
fn();// fn()独立调用,this指向全局对象,此时是undefined
window.fn();//1 fn()此时被window对象所拥有,this为window 对象字面量并不会产生自己的作用域:
var a = 20;
function foo (){
var a=1;
var obj={
a:10,
c: this.a+20
}
return obj.c;
}
window.foo()//40,此时的this指向window#Java#
凡岛公司福利 818人发布
查看2道真题和解析