JavaScript核心技术开发解密--第七章 this

当前函数的this是在函数被调用执行的时候才确定的,简言之,谁调用,this指向谁。

  1. 默认绑定

首先要介绍的是最常用的函数调用类型:独立函数调用。这是默认的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#
全部评论

相关推荐

2025-12-28 16:32
重庆邮电大学 Java
程序员花海:1.技能放最后,来面试默认你都会,技能没啥用 2.实习写的看起来没啥含金量,多读读部门文档,包装下 接LLM这个没含金量 也不要用重构这种 不会给实习生做的 3.抽奖这个还是Demo项目,实际在公司里面要考虑策略,满减,触发点,触发规则 库存 之类的,不是这个项目这么简单 4.教育背景提前,格式为 教育背景 实习 项目 技能 自我评价
简历被挂麻了,求建议
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务