前言
记录一下最近学习的一些原生 JS 方法的实现,中间会用到一些es6的语法,有兴趣的朋友可以参考阮一峰 ES6 入门教程,留个赞再走呗。
实现 call 方法
// 将方法挂在到顶层函数 Function 的原型上,这样保证都能访问
Funtion.prototype.myCall = function (...rest) {
// 获取第一个参数为目标函数
var thisArg = rest[0]
// 判断第一参数是否为原始值,如果是则通过构造函数包装成对象
var thisArgType = typeof thisArg
if (thisArgType === 'number') {
thisArg = new Number(thisArg)
} else if (thisArgType === 'string') {
thisArg = new String(thisArg)
} else if (thisArgType === 'boolean') {
thisArg = new Boolean(thisArg)
}
// 截取索引 1 开始的剩余参数
var invokeParams = rest.slice(1)
// 获取当前 this
var invokeFunc = this
// 如果 thisArg 是 null or undefined,返回当前函数执行的结构就可以
if (thisArg === null || thisArg === undefined) {
return invokeFunc(...invokeParams)
}
// 生成唯一值
var uniqueProName = Symbol(thisArg)
// 将当前 this 放到目标函数下
thisArg[uniqueProName] = invokeFunc
// 返回目标函数执行结果
return thisArg[uniqueProName](...invokeParams)
}
// 测试代码1
function test (a, b) {
var args = [].slice.myCall(arguments, a, b)
console.log(args)
}
test(1, 2)
// 测试代码2
var obj = {
name: 'wex'
}
var name = 'global'
function getName () {
console.log(this)
console.log(this.name)
}
getName()
getName.myCall(obj)
实现 apply 原生方法
Function.prototype.myApply = function (thisArg, thisArray) {
// 处理第二个参数
const paramsArray = Array.isArray(thisArray) ? thisArray : []
// 第一个参数如果为基本类型,转化为包装函数
var thisArgType = typeof thisArg
if (thisArgType === 'number') {
thisArg = new Number(thisArg)
} else if (thisArgType === 'string') {
thisArg = new String(thisArg)
} else if (thisArgType === 'boolean') {
thisArg = new Boolean(thisArg)
}
// 获取当前 this 指向
var invokeFunc = this
// 判断 目标函数 thisArg 是否为 null or undefined,如果是,返回当前函数执行结果
if (thisArg === null || thisArg === undefined) {
return invokeFunc(...paramsArray)
}
var uniqueProName = Symbol(thisArg)
thisArg[uniqueProName] = invokeFunc
return thisArg[uniqueProName](...paramsArray)
}
// 测试代码1
var num = Math.max.myApply(null, [1, 29, 10])
console.log(num)
// 测试代码2
function test (a, b, c) {
let num = Math.max.myApply(arguments, [a, b, c])
console.log(num)
}
test(1, 22, 33)
实现 bind 原生方法
Function.prototype.myBind = function (...rest) {
// 拿到绑定的函数
var boundThis = rest[0]
// 获取从 1 开始的剩余参数
var boundParams = rest.slice(1)
// 获取绑定目标的函数
var boundTargetFunc = this
// 判断绑定目标必须是函数,否则抛出错误
if (typeof boundTargetFunc !== 'function') {
throw new Error('绑定目标必须为函数')
}
// 新函数
function fBound () {
var restParams = [].slice.call(arguments)
// 获取所有参数
var allParams = [...boundParams, ...restParams]
// 通过 intanceof 判断 this 是不是 fBound 的实例
var isConstructor = this instanceof fBound
if (isConstructor) {
// 如果是,说明是通过 new 调用的
return new boundTarfetFunc(...allparams)
} else {
return boundTargetFunc.apply(boundThis, allParams)
}
}
// 返回 fBound
return fBound
}
实现 new 原生方法
function myNew(func, ...rest) {
// 创建一个空对象,并指定原型为 func.prototype
var obj = Object.create(func.prototype)
// new 构造函数时要执行的函数,同时指定 this
func.call(obj, ...rest)
// 最后返回这个对象
return obj
}
// 测试代码
function TestNew (name, age) {
this.name = name
this.age = age
}
var Test = myNew(TestNew, '小明', 20)
console.log(Test.name)