写点什么

新手模拟实现 bind

用户头像
前端树洞
关注
发布于: 2021 年 06 月 07 日

前面模拟了 call 和 apply,我们先来回顾一下,且进行一些小小的优化

模拟实现

call

我们先描述一下call是用来做什么的, 能得到什么1. 传入多个参数,第一个参数为需要改变的this指向不传时候指向window2. 改变this指向3. 会执行调用call的函数,且能传入参数4. 返回调用call的函数的执行结果
这里要优化一下,因为之前都是假设context中没有fn属性,是不行的,所以下面要确保fn的唯一性Function.prototype.myCall = function (context, ...args) { // 判断第一个参数,为null或Undefined时this指向为Window,Object(context)是因为this参数可以传入基 本数据类型,原生call会自动用Object()转换 context = context ? Object(context) : Window; // 这里需要定义fn属性确保唯一性 const fn = symbol(); // 改变this指向 context[fn] = this; // 执行函数,传入参数(这里是es6的数组解构) let result = context[fn](...args); // 函数执行完毕删除属性 delete context[fn]; // 返回函数执行的结果 return result;};
复制代码


apply

apply的实现其实就是将接收的参数修改一下即可
Function.prototype.myApply = function (context, args) { // 判断第一个参数,为null或Undefined时this指向为Window,Object(context) 是因为this参数可以传入基本数据类型,原生apply会自动用Object()转换 context = context ? Object(context) : Window; // 这里需要定义fn属性确保唯一性 const fn = symbol(); // 改变this指向 context[fn] = this; // 执行函数,传入参数(这里是es6的数组解构) let result = context[fn](...args); // 函数执行完毕删除属性 delete context[fn]; // 返回函数执行的结果 return result;};
复制代码


下面就来看看 bind 的特性和使用场景,接着模拟实现。


bind 的特性:

  1. 可以指定 this

  2. 可以传入多个参数

  3. 返回一个函数

  4. 柯里化

  5. 使用 new 运算符构造绑定函数时,忽略该值。

bind 使用场景
  1. setTimeout 中应用

var myName = "jack";function Person(name){    this.myName = name;    this.say = function() {        setTimeout(function(){            console.log("Hi, my name is " + this.myName);        }, 1000);    }} var person = new Person('peter');person.say(); // // Hi my name is jack
因为setTimeout是在全局环境中执行的,所以this指向window
下面通过bind绑定this
var myName = "jack";function Person(name){ this.myName = name; this.say = function() { setTimeout(function(){ console.log("Hi, my name is " + this.myName); }.bind(this), 1000); }} var person = new Person('peter');person.say(); // Hi my name is peter
复制代码


  1. 创建绑定函数

var name = 'jack';var person = {  name: 'peter',  getName: function (){ return this.name; }}person.getName(); // 'peter'
var result = person.getName;result(); // 'jack' 因为result是在全局中被调用的
// 这时候就可以创建一个新函数,把‘this’绑定到person对象中var resultFn = result.bind(person);resultFn(); // 'peter';
复制代码


  1. 柯里化

所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。我们来看例子吧
// 柯里化之前function add( x, y){ return x + y;}
add(1, 2); // 3
// 柯里化之后functino add(x){ return function (y){ return x + y; }}
add(1)(2); // 3
复制代码
模拟实现
Function.prototype.myBind = function (context, ...firstarg) {  // 指定调用函数的this  const self = this;  // 定义返回的函数,...secoundarg是二次传参  const fn = function (...secoundarg) {    const isNew = this instanceof fn;    context = isNew ? this : Object(context);    // 绑定this    return self.apply(context, [...firstarg, ...secoundarg]);  };  // 复制原函数的prototype到fn上  fn.prototype = Object.create(self.prototype);  // 返回一个函数  return this; };

下面再来试试上面的例子,看看结果是否一致:var name = 'jack';var person = { name: 'peter', getName: function (){ return this.name; }}person.getName(); // 'peter'
var result = person.getName;result(); // 'jack' 因为result是在全局中被调用的
// 这时候就可以创建一个新函数,把‘this’绑定到person对象中var resultFn = result.myBind(person);resultFn(); // 'peter';
----------------------------------------------------------
var myName = "jack";function Person(name){ this.myName = name; this.say = function() { setTimeout(function(){ console.log("Hi, my name is " + this.myName); }myBind(this), 1000); }} var person = new Person('peter');person.say(); // Hi my name is peter
复制代码


发布于: 2021 年 06 月 07 日阅读数: 9
用户头像

前端树洞

关注

还未添加个人签名 2020.07.16 加入

不仅能倾听,还能分解,前端,面试,nodeJS,源码都有,公众号同名(前端树洞)

评论

发布
暂无评论
新手模拟实现bind