apply & bind

举报
小妖现世 发表于 2021/07/20 01:58:40 2021/07/20
【摘要】 apply 的使用方法apply 与 call 的作用相同,基本用法如下。function fn() { console.log(this, arguments);}fn.apply('hello', ['1', '2']);// String { "hello" }// Arguments(2) ["1", "2", callee: ƒ, Symbol(Symbol.iterator):...

apply 的使用方法

applycall 的作用相同,基本用法如下。

function fn() {
  console.log(this, arguments);
}

fn.apply('hello', ['1', '2']);

// String { "hello" }
// Arguments(2) ["1", "2", callee: ƒ, Symbol(Symbol.iterator): ƒ]

apply 的实现原理

通过用法可以看出 applycall 唯一不同的就是传参方式,call 传递给调用它的函数传参靠调用时使用参数列表的方式依次传入,而 apply 是通过数组的方式传入,只需要将 call 的代码稍加改造就可以实现 apply

// context 参数为要替换的 this,args 为调用 apply 函数执行的参数
Function.prototype.apply = function (context, args) {
  context = context ? Object(context) : window;
  context.fn = this;

  // 判断是否传入参数列表,如果没传则直接执行
  if (!args) return context.fn();
  var result = eval('context.fn(' + args + ')');

  delete context.fn;

  return result;
}

bind 的使用方法

bind 函数是 Function 原型对象上的方法,bind 的作用是可以将调用它的函数内部的 this 绑定成所指定的 this,第一个参数为指定的 this,与 callapply 不同的是,调用 bind 的函数并不会执行,而是返回一个新的函数,新的函数调用时传入的参数会和 bind 调用时传入的除第一个以外的参数进行合并,并作为调用 bind 的函数执行的参数,下面是 bind 的基本用法。


var obj = {
  name: 'Shen'
};

function sayName() {
  console.log(this.name);
}

var bindFn = sayName.bind(obj);
bindFn();
// Shen


var obj = {
  name: 'Shen'
};

function animal(name, age) {
  console.log(this.name + ' have a ' + name + ' is ' + age + ' years old.');
}

var bindFn = animal.bind(obj, 'cat');
bindFn(2);
// Shen have a cat is 2 years old.


var obj = {
  name: 'Shen'
};

function Animal(name, age) {
  this.name = name;
  this.age = age;
}

// 动物类别为哺乳类
Animal.prototype.category = 'mammalia';

var BindFn = Animal.bind(obj, 'cat');
var cat = new BindFn(2);

console.log(cat); // Animal {name: "cat", age: 2}
console.log(cat.category); // mammalia

bind 的原理

从上面的例子已经可以看出 bind 不但能绑定 this,收集参数,返回的函数既可以直接调用,又可以作为构造函数实例化对象,而实例化的对象的方式,bind 绑定的 this 不生效,this 指向被创建的实例,实例依然可以找到原来函数原型上的属性和方法,根据 bind 的特性,模拟实现的代码如下。


// context 参数为要绑定的 this
Function.prototype.bind = function (context) {
  // this 为调用 bind 的函数
  var self = this;

  // 收集除了 context 以外所有的参数
  var bindArgs = Array.prototype.slice.call(arguments, 1);

  // 返回的新函数 fBound
  function fBound() {
    // 收集 fBound 的参数
    var args = Array.prototype.slice.call(arguments);

    // 执行调用 bind 的函数
    // 若是普通函数调用,this 为 context,若是作为构造函数则 this 为实例
    self.apply(this instanceof fBound ? this : context, bindArgs.concat(args));
  }

  // 用来继承的中间函数
  function fNOP() {}

  // 作为构造函数调用 fBound 时,为了实例可以找到调用 bind 函数的原型对象,进行继承
  if (this.prototype) {
    // Function.prototype 为函数,可以调用 bind,当时没有原型对象,所以要判断
    fNOP.prototype = this.prototype;
    fBound.prototype = new fNOP();
  }

  return fBound;
}
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。