新手模拟实现bind

这是我参与更文挑战的第2天,活动详情查看: 更文挑战.

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

模拟实现
call
我们先描述一下call是用来做什么的, 能得到什么
1. 传入多个参数,第一个参数为需要改变的this指向不传时候指向window
2. 改变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

复制代码
© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享