上篇文章介绍了this的隐式绑定(implicit binding),接着介绍this其余三种绑定方式segmentfault
默认绑定 (Default Binding)app
显式绑定 (Explicit Binding)ide
new绑定(new Binding)函数
这个是最简单的绑定,最经常使用的调用类型:独立函数调用测试
function foo() { console.log( this.a ); } var a = 2; foo(); // 2
首先foo()在全局做用域中被调用,根据调用域(call-site),此时this绑定到了全局,因此结果很明显。this
但在严格模式下,默认绑定不起做用prototype
function foo() { "use strict"; console.log( this.a ); } var a = 2; foo(); // TypeError: `this` is `undefined`
显式绑定用到了call()和apply()
方法,由于能够直接指定this的绑定对象,所以称之为显式绑定。code
function foo() { console.log( this.a ); } var obj = { a: 2 }; foo.call( obj ); // 2
经过foo.call(),咱们能够在调用foo时强制把它this绑定到obj上。对象
由于咱们强制把foo的this绑定到了obj,不管以后如何调用bar,以后的操做并不会覆盖以前的,它总会在obj
上调用foo。ci
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来调用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将不知所措了。
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),因此显式绑定的优先级更高。
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绑定 > 显式绑定 > 隐式绑定