JavaScript中的new,bind,call,apply的简易实现
Function原型链中的apply,call和bind方法是 JavaScript 中相当重要的概念,与this关键字密切相关,相当一部分人对它们的理解还是比较浅显,所谓js基础扎实,绕不开这些基础常用的API,这次让我们来了解它们吧!
实现new运算符
原理
new 关键字会进行如下的操作:
- 创建一个空的简单JavaScript对象(即{});
- 链接该对象(设置该对象的
constructor)到另一个对象 ; - 将步骤1新创建的对象作为
this的上下文 ; - 如果该函数没有返回对象,则返回
this。
实现代吗
function _new(fn, ...args) {
if (typeof fn !== "function") {
throw TypeError("fn is not");
}
const obj = Object.create(fn.prototype);
const res = fn.call(obj, ...args);
const isObject = typeof res === "object" && res !== null;
return isObject ? res : obj;
}
实现bind方法
语法
function.bind(thisArg[, arg1[, arg2[, ...]]])
参数
thisArg
调用绑定函数时作为 this 参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用 bind 在 setTimeout 中创建一个函数(作为回调提供)时,作为 thisArg 传递的任何原始值都将转换为 object。如果 bind 函数的参数列表为空,或者thisArg是null或undefined,执行作用域的 this 将被视为新函数的 thisArg。
arg1, arg2, ...
当目标函数被调用时,被预置入绑定函数的参数列表中的参数。
返回值
返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。
原理
bind() 函数会创建一个新的绑定函数(bound function,BF)。绑定函数是一个 exotic function object(怪异函数对象,ECMAScript 2015 中的术语),它包装了原函数对象。调用绑定函数通常会导致执行包装函数。
绑定函数具有以下内部属性:
[[BoundTargetFunction]]- 包装的函数对象[[BoundThis]]- 在调用包装函数时始终作为this值传递的值。[[BoundArguments]]- 列表,在对包装函数做任何调用都会优先用列表元素填充参数列表。[[Call]]- 执行与此对象关联的代码。通过函数调用表达式调用。内部方法的参数是一个this值和一个包含通过调用表达式传递给函数的参数的列表。
当调用绑定函数时,它调用 [[BoundTargetFunction]] 上的内部方法 [[Call]],就像这样 Call(boundThis, args)。其中,boundThis 是 [[BoundThis]],args 是 [[BoundArguments]] 加上通过函数调用传入的参数列表。
代码
有两种实现bind的方法,下面第一种不支持使用new调用新创建的构造函数,而第二种支持。
方法一
Function.prototype.myBind = function () {
const thatFunc = this,
thatArg = arguments[0],
slice = Array.prototype.slice;
let args = slice.call(arguments, 1);
if (typeof thatFunc !== "function") {
throw new TypeError(
"Function.prototype.bind - what is trying to be bound is not callable"
);
}
return function () {
var funcArgs = args.concat(slice.call(arguments));
return thatFunc.apply(thatArg, funcArgs);
};
};
方法二
Function.prototype.myBind = function (otherThis) {
if (typeof this !== "function") {
throw new TypeError(
"Function.prototype.bind - what is trying to be bound is not callable"
);
}
const ArrayPrototypeSlice = Array.prototype.slice;
let baseArgs = ArrayPrototypeSlice.call(arguments, 1),
baseArgsLength = baseArgs.length,
fToBind = this,
fNOP = function () {},
fBound = function () {
baseArgs.length = baseArgsLength; // reset to default base arguments
baseArgs.push.apply(baseArgs, arguments);
return fToBind.apply(
fNOP.prototype.isPrototypeOf(this) ? this : otherThis,
baseArgs
);
};
if (this.prototype) {
fNOP.prototype = this.prototype;
}
fBound.prototype = new fNOP();
return fBound;
};
实现call方法
语法
func.call([thisArg[, arg1, arg2, ...argN]])
参数
thisArg
可选的。在 function 函数运行时使用的 this 值。请注意,this可能不是该方法看到的实际值:如果这个函数处于非严格模式下,则指定为 null 或 undefined 时会自动替换为指向全局对象,原始值会被包装。
arg1, arg2, ...
指定的参数列表。
返回值
使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined。
实现代码
Function.prototype.myCall = function (ctx, ...arg) {
if (ctx === null || ctx === undefined) {
ctx = window
} else if (typeof ctx !== 'object' || typeof ctx !== 'function') {
ctx = Object(ctx)
}
const tmp = Symbol('tmp');
ctx[tmp] = this;
const result = ctx[tmp](...arg);
delete ctx[tmp];
return result;
};
apply方法的实现
注意:
apply()方法的作用和call()方法类似,区别就是call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。
Function.prototype.myApply = function (ctx, arg) {
if (ctx === null || ctx === undefined) {
ctx = window
} else if (typeof ctx !== 'object' || typeof ctx !== 'function') {
ctx = Object(ctx)
}
const tmp = Symbol('tmp');
ctx[tmp] = this;
const result = ctx[tmp](...arg);
delete ctx[tmp];
return result;
};
参考书籍
- MDN-new运算符
- MDN-Function.prototype.bind()
- MDN-Function.prototype.call()
- MDN-Function.prototype.apply()
JavaScript中的new,bind,call,apply的简易实现的更多相关文章
- 理解JavaScript中的arguments,callee,caller,apply
arguments 该对象代表正在执行的函数和调用它的函数的参数. [function.]arguments[n] 参数function :选项.当前正在执行的 Function 对象的名字. n : ...
- [转] 理解 JavaScript 中的 Array.prototype.slice.apply(arguments)
假如你是一个 JavaScript 开发者,你可能见到过 Array.prototype.slice.apply(arguments) 这样的用法,然后你会问,这么写是什么意思呢? 这个语法其实不难理 ...
- JavaScript中callee与caller,apply与call解析
1. arguments.callee 1.1 解释 返回正被执行的 Function 对象,也就是所指定的 Function 对象的正文. 1,.2 说明 callee 属性的初始值就是正被执行的 ...
- javascript中函数的call,apply及bind方法
call 方法调用一个对象的一个方法,以另一个对象替换当前对象.call([thisObj[,arg1[, arg2[, [,.argN]]]]])参数thisObj可选项.将被用作当前对象的对象. ...
- javascript中this、new、apply和call详解
如果在javascript语言里没有通过new(包括对象字面量定义).call和apply改变函数的this指针,函数的this指针都是指向window的,重要的话要说三遍.... 讲解this指针的 ...
- javascript 中的 arguments,callee.caller,apply,call 区别
记录一下: 1.arguments是一个对象, 是函数的一个特性,只有在函数内才具有这个特性,在函数外部不用使用. 举例: function test(){ alert(typeof argume ...
- Javascript中call函数和apply函数的使用
Javascript 中call函数和apply的使用: Javascript中的call函数和apply函数是对执行上下文进行切换,是将一个函数从当前执行的上下文切换到另一个对象中执行,例如: so ...
- 深入浅出 妙用Javascript中apply、call、bind
apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(context)而存在的,换句话说,就是为了改变函数体内部 this 的指向. Jav ...
- 【优雅代码】深入浅出 妙用Javascript中apply、call、bind
这篇文章实在是很难下笔,因为网上相关文章不胜枚举. 巧合的是前些天看到阮老师的一篇文章的一句话: “对我来说,博客首先是一种知识管理工具,其次才是传播工具.我的技术文章,主要用来整理我还不懂的知识.我 ...
- Javascript中call,apply,bind方法的详解与总结
在 javascript之 this 关键字详解 文章中,谈及了如下内容,做一个简单的回顾: 1.this对象的涵义就是指向当前对象中的属性和方法. 2.this指向的可变性.当在全局作用域时,thi ...
随机推荐
- Oracle VM VirtualBox安装CentOS7
安装VirtualBox6.0 下载地址:https://www.virtualbox.org/ 新建虚拟机 类型:Linux 版本:Other Linux(64-bit)----如果没有出现64-b ...
- ForkJoinPool大型图文现场(一阅到底 vs 直接收藏)
知识回顾 并发工具类我们已经讲了很多,这些工具类的「目标」是让我们只关注任务本身,并且忽视线程间合作细节,简化了并发编程难度的同时,也增加了很多安全性.工具类的对使用者的「目标」虽然一致,但每一个工具 ...
- Spring Cloud基础
1.网站架构演变过程 传统架构(单点应用SSM或SSH)→分布式架构(项目拆分)→SOA架构(面向服务架构)→微服务架构 2.微服务概述 2.1SOA架构 面向服务的架构(SOA)是一个组件模型,它将 ...
- 你要是还学不会,请提刀来见 Typora+PicGo+Gitee + node.js 打造个人高效稳定优雅图床
你要是还学不会,请提刀来见 Typora+PicGo+Gitee + node.js 打造个人高效稳定优雅图床 经过前面两弹的介绍,相信大家对图床都不陌生了吧, 但是小魔童觉得这样做法还是不方便,使用 ...
- 【python3.x】发送自动化测试报告邮件
SMTP(Simple Mail Transfer Protocol)即简单邮件传输协议,它是一组用于由源地址到目的地址传送邮件的规则,由它来控制信件的中转方式.python的smtplib提供了 ...
- 微信小程序滚动条设置
隐藏滚动条 ::-webkit-scrollbar { width: 0rpx; height: 0rpx; background-color: transparent; } 其实设置为宽高为 0 或 ...
- Kubernetes-7.Ingress
docker version:20.10.2 kubernetes version:1.20.1 本文概述Kubernetes Ingress基本原理和官方维护的Nginx-Ingress的基本安装使 ...
- 【转载】markdown数学常用公式箭头符号
来源1:https://www.jianshu.com/p/3f01c5658356 来源2:https://blog.csdn.net/smstong/article/details/4434063 ...
- there is nothing(i春秋CTF题解)
(1)打开页面,显示为:there is nothing (2)抓包发现提示 (3)hint:ip,Large internal network 意为最大的内网网段IP,hint: ip,Larg ...
- 锐捷RG-UAC统一上网行为管理审计系统账号密码泄露漏洞 CNVD-2021-14536
一:产品介绍: 锐捷 RG-UAC 统一上网行为管理审计系统 锐捷统一上网行为管理与审计RG-UAC系列是星网锐捷网络有限公司自主研发的上网行为管理与审计产品,以路由.透明.旁路或混合模式部署在网络的 ...