显示绑定
我们通常会碰见丢失绑定的情况,例如系统函数setTimeOut
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // a是全局对象的属性
setTimeout( obj.foo, 100 ); // "oops, global
call和apply能够显示的绑定函数this的指向,他们很相似,不同的是传入的函数参数的不同。
function fn(a,b){
console.log(this.name);
}
var a ={
name:'deng',
fn:fn
}
fn.call(a,1,2);
fn.apply(a,[1,2]);
但是此时还是无法解决回调函数中的绑定丢失问题。我们可以通过在函数里包装一层解决这个问题(硬绑定)
function foo() {
console.log( this.a );
}
var obj = {
a: 2,
foo: foo
};
function fn(){
foo.call(obj);
}
var a = "oops, global"; // a是全局对象的属性
setTimeout( fn, 100 ); // 2
fn.call(windows); // 2 即使在这里call也无法改变内部绑定对象
变式: 创建一个可以重复使用的函数
var obj = {
name:'deng',
fn:bar
}
var obj2 = {
name:'deng2',
fn:bar
}
function bind(fn,o){
return function(){
return fn.call(o); //这里按道理来讲已经bind函数执行已经结束,但是我们需要形参O,之所以能找到,因为闭包
}
}
function fun(){
console.log(this.name);
}
var bar =bind(fun,obj);
bar.call(obj2); // deng
由于硬绑定是一种非常常用的模式,所以在ES5中提供了内置的方法 Function.prototype.bind。
用法:
const person = {
name: 'Bob'
};
function greet() {
console.log(`Hello, ${this.name}`);
}
const greetBob = greet.bind(person);
greetBob(); // 输出 'Hello, Bob'
API调用的“上下文” 第三方库的许多函数,以及JavaScript语言和宿主环境中许多新的内置函数,都提供了一个可选的参数,通常被称为“上下文”(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
new 绑定
传统面向对象语言,构造函数时类中的特殊方法。
而JS中,它们只是被new操作符调用的普通函数而已。
包括内置对象函数在内的所有函数都可以用new来调用,这种函数调用被称为构造函数调用。这里有一个重要但是非常细微的区 别:实际上并不存在所谓的“构造函数”,只有对于函数的“构造调用”。
使用new调用函数会执行以下操作
- 创建一个全新对象
- 新对象会执行原型连接
- 函数的this会绑定新对象
- 如果函数没有返回其他对象,那么new表达式中的函数执行会自动返回这个新对象。
我们来看看绑定的优先级
1.显示绑定高于隐式绑定
案例:
var user = {
name: 'user',
foo: function(){
console.log(this.name)
}
}
var user1 = {
name: 'user1',
foo: function(){
console.log(this.name)
}
}
user.foo.call(user1)//user1
2.new高于隐式绑定
var user = {
name: 'lisa',
foo: function () {
console.log(this)
}
}
new user.foo() //foo{}
Function.prototype.bind(…)会创建一个 新的包装函数,这个函数会忽略它当前的this绑定(无论绑定的对象是什么),并把我们 提供的对象绑定到this上。 这样看起来硬绑定(也是显式绑定的一种)似乎比new绑定的优先级更高,无法使用new 来控制this绑定。
实际上会判断硬绑定函数是否是被new调用,如果是的话就会使用新创建 的this替换硬绑定的this。
3.new高于显示绑定
function bar(){
console.log(this)
}
var fn = bar.bind('hello')
new fn() // bar
综上,优先级顺序为
new关键字 > 显式绑定 > 隐式绑定 > 默认绑定