独立函数调用
function foo() { console.log( this.a ); } var a = 2 foo() // 2本例中,函数调用时应用了this的默认绑定,因此this指向全局对象
在代码里,foo() 是直接使用不带任何修饰的函数引用进行调用的,因此只能使用默认绑定,无法应用其他规则
注意: 如果使用严格模式(strict mode),那么全局对象将无法使用默认绑定,因此this会绑定到undefined
function foo() { "use strict" console.log( this.a ) } var a = 2 foo() // typeError: this is undefined这里有一个微妙但是非常重要的细节,虽然this的绑定规则完全取决于调用位置,但是只有foo() 运行在非 strict mode 模式下时(在非严格模式下定义),默认绑定才会绑定到全局对象; 跟foo()的调用位置是不是在严格模式下无关:
// 如何理解??????? 上面那段话 function foo() { console.log( this.a ); } var a = 2; (function() { "use strict"; foo(); // 2 })()当函数有上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因为调用foo() 时this被绑定到obj,因此 this.a 和 obj.a 是一样的。
call() 和 apply()
function foo() { console.log( this.a ); } 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 setTimeout(bar, 100) // 2 // 即使如下使用 硬绑定的 bar 也不可能再修改它的值 bar.bind(window) // 2分析下这种变种是如何工作的: 手动创建函数 bar,bar函数中给foo显示绑定了obj,之后无论怎样调用bar 总会显示绑定到obj上。这种绑定是一种显示的强制绑定,称为硬绑定
硬绑定的典型应用场景:
场景1.就是创建一个包裹函数,传入所有的参数并返回接收到的所有值,如下:
function foo(something) { console.log( this.a, something ); return this.a + something; } var obj = { a:2 }; var bar = function() { return foo.apply( obj, arguments ); }; var b = bar( 3 ); // 2 3场景2.创建一个可以重复使用的辅助函数
function foo(something) { console.log(this.a, something) return this.a + something } function bind(fn, obj) { return function () { return fn.apply(obj, arguments) } } var obj = {a: 2} var bar = bind(foo, obj) var b = bar(3) // 2 3 console.log(b) // 5ES5中提供了内置的方法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) // 5bind 会返回一个硬编码的新函数,它会把参数设置为this的上下文并调用原始函数
API调用的上下文第三方库的许多函数,以及 JavaScript 语言和宿主环境中许多新的内置函数,都提供了一 个可选的参数,通常被称为“上下文”(context),其作用和 bind(…) 一样,确保你的回调 函数使用指定的 this。
例如forEach、map 等
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这些函数实际上就是通过 call(…) 或者 apply(…) 实现了显式绑定,这样你可以少些一些 代码。
new 是最后一种可以影响函数调用时this绑定行为的方法,我们称之为new绑定
使用new来调用函数或者说发生构造函数调用时,会自动执行下面的操作
创建或者说构造一个全新的对象这个新对象会被执行[[原型]]连接(暂时忽略)这个新对象会绑定到函数调用的this如何函数没有返回其他对象,那么new 表达式中的函数调用会自动返回这个新对象。重点看1 3 4 步,2先不进行详细讲解,思考下面代码:
function foo(a) { this.a = a; } var bar = new foo(2); console.log( bar.a ); // 2使用new来调用调用foo(…) 时,我们会构造一个新对象bar,并把他绑定到foo(…)调用中的this上
找到函数的调用位置并判断应当应用哪条规则,如果某个位置可以应用多条规则该怎么办,为了解决这个问题,就必须给这些规则设定优先级。
首先,默认绑定 优先级最低
比较 隐式绑定 和 显示绑定
=》 显示绑定优先级更高
比较 new绑定 和 隐式绑定
=》 new绑定优先级更高