Contents

this的绑定

Contents

javascriptthis绑定有以下几种方式

默认绑定
function foo(){
    console.log(this.a);
}
var a = 1;
foo(); // 1

以上绑定代码即为this的默认绑定,当函数没有其他绑定时,此时this指向window对象;

隐式绑定

隐式绑定需要考虑的是调用位置是否有上下文对象.如下代码所示:

function foo(){
    console.log(this.a);
}
var obj = { 
    a:'obj',
    foo:foo
}
obj.foo(); // obj

在上述代码中foo函数作为一个值被赋予到了obj对象的foo属性中,此时的this指向obj这个对象,调用时

打印的this.aobj.a为obj;再如下代码

function foo() {
  console.log(this.a);
}
var obj2 = {
  a: 'obj2',
  foo: foo
}
var obj1 = {
  a: 'obj1',
  obj2: obj2
}
obj1.obj2.foo(); // obj2

foo函数是obj2foo属性的值,上述代码中obj1通过调用自己的obj2属性来调用obj2.foo,打印出的值是obj2,可见对对象属性引用链中只有上一层或者说是最后一层在调用位置起作用

隐式丢失

​ 在隐式绑定中存在隐式丢失这个问题,被隐式绑定的函数会丢失其隐式绑定对象,也就是说此时函数会应用默认绑定,从而把this绑定到全局对象或者undefined上,取决于是否为严格模式;

function foo() {
    console.log(this.a);
}
function doFoo(fn) {
    fn();
}
var obj = {
    a: 'obj',
    foo: foo
}
var a = 'global this';
doFoo(obj.foo); // global this
doFoo.call(window,obj.foo); // global this

​ 在上述代码中调用doFoo传入obj.foo此时fn=obj.foo(在AO对象中)可以看作一个隐式赋值,此时doFoothis指向window,所以打印出来golbal this

​ 如果把函数传入语言内置的函数而不是自己声明的函数,结果是一样的,比如setTimeout函数:

setTimeout(obj.foo,100); // global this
// 伪代码如下
// function  setTimeout(fn,delay) {
//   // 等待delay
//   fn();
// }
显示绑定

显示绑定可以借助call,apply函数完成,代码如下:

function foo(){
    console.log(this.a)
}
var obj = {
    a:'obj'
}
foo.call(obj); // obj
foo.apply(obj); // obj

​ 通过调用callapply可以在调用foo时前置把它的this绑定到obj上;

​ 在这里还有个概念装箱:如果传入了一个原始值(字符串类型,布尔类型或者数字类型)来当做his的绑定对象,这个原始值会被转换成它对应的对象形式(new String()…).

但显示绑定也无法解决丢失绑定的问题,此时显示绑定的一个变种硬绑定可以解决这个问题

硬绑定
function foo() {
  console.log(this.a);
}
var obj = {
  a: 'obj'
}
var bar = function () {
  return foo.call(obj)
}
bar();

​ 在上述代码中创建了一个bar函数,每次调用bar都会在obj上调用foo这种绑定是一种显示强制绑定,称之为硬绑定.

​ 硬绑定的典型应用场景就是创造一个包裹函数,负责接收参数并返回值,由于硬绑定是一种非常常用的模式,所以es5提供了内置方法Function.prototype.bind,应用方法如下

function foo(something) {
  console.log(this.a + something);
}
var obj = {
  a: 'obj'
}
foo.bind(obj)('  something'); // obj somehing

bind会返回一个硬编码的新韩淑,它会把指定参数者只为this上下文并调用原始函数;

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

使用new调用foo时会构造一个新对象并把它绑定到foo调用中的this上.new是最后一种可以影响函数调用时this绑定行为的方法.

读《你不知道的JavaScript 上卷》笔记记录