如果判定 this 又混乱了,就从头再读一遍……
作者:互联网
this call apply bind
this
调用点
this 是完全根据调用点(函数是如何被调用的)而绑定的。
function baz() {
// 调用栈是: `baz`
// 我们的调用点是 global scope(全局作用域)
console.log( "baz" );
bar(); // <-- `bar` 的调用点
}
function bar() {
// 调用栈是: `baz` -> `bar`
// 我们的调用点位于 `baz`
console.log( "bar" );
foo(); // <-- `foo` 的 call-site
}
function foo() {
// 调用栈是: `baz` -> `bar` -> `foo`
// 我们的调用点位于 `bar`
console.log( "foo" );
}
baz(); // <-- `baz` 的调用点
可以通过 debugger 来获取调用链
this的四种规则
1. 默认绑定
对此方法调用的 this
实施了 默认绑定,所以使 this
指向了全局对象。
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
严格模式下,
function foo() {
"use strict";
console.log( this.a );
}
var a = 2;
foo(); // TypeError: `this` is `undefined`
2. 隐含绑定
调用点是否有一个环境对象?
调用点 使用 obj
环境来 引用 函数,所以你 可以说 obj
对象在函数被调用的时间点上“拥有”或“包含”这个 函数引用。
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
obj.foo(); // 2
注意,只有对象属性引用链的最后一层影响调用点。
function foo() {
console.log( this.a );
}
var obj2 = {
a: 42,
foo: foo
};
var obj1 = {
a: 2,
obj2: obj2
};
obj1.obj2.foo(); // 42
3. 隐含丢失
当一个 隐含绑定 丢失了它的绑定,这通常意味着它会退回到 默认绑定, 根据 strict mode
的状态,其结果不是全局对象就是 undefined
。
bar
似乎是 obj.foo
的引用,但实际上它只是另一个 foo
本身的引用而已。
另外,起作用的调用点是 bar()
,因此this指向全局对象。
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var bar = obj.foo; // 函数引用!
var a = "oops, global"; // `a` 也是一个全局对象的属性
bar(); // "oops, global"
function foo() {
console.log( this.a );
}
function doFoo(fn) {
// `fn` 只不过 `foo` 的另一个引用
fn(); // <-- 调用点!
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // `a` 也是一个全局对象的属性
doFoo( obj.foo ); // "oops, global"
3. 明确绑定
函数拥有 call(..)
和 apply(..)
方法。
它们接收的第一个参数都是一个用于 this
的对象,之后使用这个指定的 this
来调用函数。
function foo() {
console.log( this.a );
}
var obj = {
a: 2
};
foo.call( obj ); // 2
如果你传递一个简单基本类型值(string
,boolean
,或 number
类型)作为 this
绑定,那么这个基本类型值会被包装在它的对象类型中(分别是 new String(..)
,new Boolean(..)
,或 new Number(..)
)。这通常称为“封箱(boxing)”。
4. 硬绑定
function foo() {
console.log( this.a );
}
var obj = {
a: 2
};
var bar = function() {
foo.call( obj );
};
bar(); // 2
setTimeout( bar, 100 ); // 2
// `bar` 将 `foo` 的 `this` 硬绑定到 `obj`
// 所以它不可以被覆盖
bar.call( window ); // 2
实现bind:
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
// 简单的 `bind` 帮助函数
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 ); // 5
各种绑定的优先级
明确绑定 的优先级高于 隐含绑定:
function foo() {
console.log( this.a );
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3,
foo: foo
};
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2
new绑定 优先级高于 隐含绑定
function foo(something) {
this.a = something;
}
var obj1 = {
foo: foo
};
var obj2 = {};
obj1.foo( 2 );
console.log( obj1.a ); // 2
obj1.foo.call( obj2, 3 );
console.log( obj2.a ); // 3
var bar = new obj1.foo( 4 );
console.log( obj1.a ); // 2
console.log( bar.a ); // 4
按照优先级顺序 判定this
-
函数是通过
new
被调用的吗(new 绑定)?如果是,this
就是新构建的对象。var bar = new foo()
-
函数是通过
call
或apply
被调用(明确绑定),甚至是隐藏在bind
硬绑定 之中吗?如果是,this
就是那个被明确指定的对象。var bar = foo.call( obj2 )
-
函数是通过环境对象(也称为拥有者或容器对象)被调用的吗(隐含绑定)?如果是,
this
就是那个环境对象。var bar = obj1.foo()
-
否则,使用默认的
this
(默认绑定)。如果在strict mode
下,就是undefined
,否则是global
对象。var bar = foo()
例外
-
传递
null
或undefined
作为call
、apply
或bind
的this
绑定参数,那么这些值会被忽略掉,取而代之的是 默认绑定 规则将适用于这个调用。利用
标签:bar,log,绑定,判定,混乱,var,console,foo,从头 来源: https://www.cnblogs.com/peekapoooo/p/14408947.html