上篇文章介绍了this的隐式绑定(implicit binding),接着介绍this其他三种绑定方式
- 默认绑定 (Default Binding)
- 显式绑定 (Explicit Binding)
- new绑定(new Binding)
默认绑定 (Default Binding)
这个是最简单的绑定,最常用的调用类型:独立函数调用
function foo() {
console.log( this.a );
}
var a = 2;
foo(); // 2
首先foo()在全局作用域中被调用,根据调用域(call-site),此时this绑定到了全局,所以结果很明显。
但在严格模式下,默认绑定不起作用
function foo() {
"use strict";
console.log( this.a );
}
var a = 2;
foo(); // TypeError: `this` is `undefined`
显式绑定 (Explicit Binding)
显式绑定用到了call()和apply()
方法,因为可以直接指定this的绑定对象,因此称之为显式绑定。
function foo() {
console.log( this.a );
}
var obj = {
a: 2
};
foo.call( obj ); // 2
通过foo.call(),我们可以在调用foo时强制把它this绑定到obj上。
硬绑定(Hard Binding)
因为我们强制把foo的this绑定到了obj,无论之后如何调用bar,之后的操作并不会覆盖之前的,它总会在obj
上调用foo。
function foo() {
console.log( this.a );
}
var obj = {
a: 2
};
var bar = function() {
foo.call( obj );
};
bar(); // 2
setTimeout( bar, 100 ); // 2
// `bar` hard binds `foo`'s `this` to `obj`
// so that it cannot be overriden
bar.call( window ); // 2
硬绑定的应用场景就是创建一个包裹函数,负责接收参数并返回值:
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
console.log( b ); // 5
另一种使用方法是创建一个可以重复使用的辅助函数
function foo(something) {
console.log( this.a, something );
return this.a + something;
}
// simple `bind` helper
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
由于硬绑定是非常常用的,所以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
new Binding
使用new来调用foo()时,我们会构造一个新对象并把它绑定到foo()调用中的this上。
function foo(n) {
this.studentNum = n;
this.name = 'cnio'
}
var bar = new foo(1)
console.log(bar) // foo {studentNum: 1, name: "cnio"}
如果foo原型链上也有内容,比如添加
foo.prototype.getName = function() {
return this.name;
}
在控制台打印出的proto
中,就有getName属性。
使用new关键字时,会发生如下几个步骤
- 创建一个全新的对象。
- 这个新对象会被执行[[Prototype]]连接。
- 这个新对象会绑定到函数调用的this。
- 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。
优先级比较
前面已经了解了this绑定的四条规则,但是这几种某次应用了多条该怎么办?所以需要测试一下优先级,也就是谁的权利更大些,就听谁的,否则小弟this将不知所措了。
隐式绑定 VS 显式绑定
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
当我们使用call(obj2)
显式绑定时,输出的值为obj2
的值(a=3),所以显式绑定的优先级更高。
new绑定 VS 隐式绑定
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
可以看到,new绑定的优先级>
隐式绑定
那么new绑定的优先级与显式绑定优先级呢?因为new和apply/call无法一起使用,但硬绑定也是显式绑定的一种,可以替换测试
function foo(something) {
this.a = something;
}
var obj1 = {};
var bar = foo.bind( obj1 );
bar( 2 );
console.log( obj1.a ); // 2
var baz = new bar( 3 );
console.log( obj1.a ); // 2
console.log( baz.a ); // 3
new修改了硬绑定调用bar()中的this,代码感觉无法修改this绑定,但是又的确修改了this绑定,这个很特殊,理论上我们可以认为new绑定优先级>
显式绑定
综上,优先级比较如下
new绑定 > 显式绑定 > 隐式绑定
原文链接:https://icoding.net/topic/65....
(完)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。