【《你不知道的JS(中卷)》】二、this详解

2021-02-04 17:14

阅读:524

标签:操作符   构造函数   var   efi   使用   time   OLE   on()   glob   

二、this全面解析:

? 这一章将详细分析this的各种绑定方式。

一)、调用位置:

? 要理解绑定方式,首先需要理解 调用位置

? \(调用位置\to 调用栈(为了到达当前执行位置所调用的所有函数)\)

function baz() {
	// 调用栈: baz
	// 调用位置: 全局作用域
	console.log("baz");
	bar();
}

function bar() {
	// 调用栈: baz -> bar
	// 调用位置: baz函数中
	console.log("bar");
	foo();
}

function foo() {
	//  调用栈: baz -> bar -> foo
	// 调用位置: bar函数中
	console.log("foo");
}

baz();

二)、绑定规则:

1、默认绑定:

? 可以看作是当其他绑定规则无法应用时的默认规则:this指向全局作用域(use strict时为undefined)

2、隐式绑定:

? 应用于调用位置具有上下文对象时。

function foo() {
	console.log(this.a);
}

var obj = {
  a: 2,
  foo: foo
};

obj.foo(); // 2

尽管在JS中不能说obj对象拥有foo函数。但是在上列中调用位置会使用obj上下文调用函数,在函数调用时可以说obj“拥有”这个函数。

  • 对象属性引用链中只有栈顶会影响调用位置。

引用丢失:

var obj = {
  a: 2,
  foo: foo
};

// bar是一个obj.foo的引用,但实际上是foo的引用,因此此时适用于默认绑定
var bar = obj.foo;

var a = "oops, global";

bar(); // oops, global
  • 引用丢失常发生在回调函数中,如果给回调函数传obj.foo,实际上函数引用的就是foo。

3、显式绑定:

call(), apply()方法,将对象绑定到this,接着在调用函数时指定这个this。

function foo() {
	console.log(this.a);
}

var obj = {
	a:2
};

foo.call(obj); // 2
  • 因为可以直接指定this的绑定对象,因此被称为显式绑定。

但是显式绑定仍然无法解决 丢失绑定问题。

1)、硬绑定:

// ...
var bar = function() {
	foo.call(obj);
}

setTimeout(bar, 100000);

创建一个包裹函数,传入所有的参数并返回接收到的所有值。

  • 由于硬绑定非常常用,因此ES5中内置了bind方法:

    var bar = foo.bind(obj);
    

2)、API调用的“上下文”:

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

function foo(el) {
	console.log(el, this.id);
}

var obj = {
	id: "awesome";
};

// 调用foo(...)时把this绑定到obj
[1, 2, 3].forEach(foo, obj);
// 1 awesome 2 awesome 3 awesome

4、new绑定:

? 在传统的面向对象语言中,new是构造函数的特殊方法。而在JS中,构造函数只是一些使用new操作符时被调用的函数。它们并不会属于某个类,也不会实例化一个类。更不是特殊的函数类型,只是被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>显式>隐式>默认\)

四)、绑定例外:

1、被忽略的this:

? 将null或者undefined作为this的绑定对象传入call、apply或者bind,这些值在调用时会被忽略,实际应用的是默认绑定规则。

2、间接引用:

function foo() {
	console.log(this.a);
}

var a = 2;
var o = {a: 3, foo: foo};
var p = {a: 4};
o.foo() // 3
// 赋值表达式的返回值是foo的引用,因此调用位置为foo(),因此应用默认绑定
(p.foo = o.foo); // 2

3、软绑定:

五)、this词法:

箭头函数:

? 箭头函数不适用于this的规则,而是由外层(函数或者全局来决定this)。

function foo() {
	return (a) => {
		console.log(this.a);
	};
}

var obj1 = {
	a: 2
};

var obj2 = {
	a: 3
};

var bar = foo.call(obj1);
bar.call(obj2); // 2

箭头函数可以像bind(..)一样确保函数的this被绑定到指定对象,此外,它用更常见的词法作用域取代了传统的this机制。

  • this风格与词法作用域不应该混用!

【《你不知道的JS(中卷)》】二、this详解

标签:操作符   构造函数   var   efi   使用   time   OLE   on()   glob   

原文地址:https://www.cnblogs.com/enmac/p/13138271.html


评论


亲,登录后才可以留言!