call,apply,bind 深入

显示绑定

我们通常会碰见丢失绑定的情况,例如系统函数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调用函数会执行以下操作

  1. 创建一个全新对象
  2. 新对象会执行原型连接
  3. 函数的this会绑定新对象
  4. 如果函数没有返回其他对象,那么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关键字 > 显式绑定 > 隐式绑定 > 默认绑定

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值