新手模拟实现 bind
发布于: 2021 年 06 月 07 日
前面模拟了 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 的特性:
可以指定 this
可以传入多个参数
返回一个函数
柯里化
使用 new 运算符构造绑定函数时,忽略该值。
bind 使用场景
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
复制代码
创建绑定函数
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';
复制代码
柯里化
所谓"柯里化",就是把一个多参数的函数,转化为单参数函数。我们来看例子吧
// 柯里化之前
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
版权声明: 本文为 InfoQ 作者【前端树洞】的原创文章。
原文链接:【http://xie.infoq.cn/article/bab4bce273fe901331465bded】。
本文遵守【CC BY-NC】协议,转载请保留原文出处及本版权声明。
前端树洞
关注
还未添加个人签名 2020.07.16 加入
不仅能倾听,还能分解,前端,面试,nodeJS,源码都有,公众号同名(前端树洞)
评论