call/apply/bind底层是c++实现的,js能达到一个模拟器的效果,这里不过多的考虑边界问题
实现call
/**
* 简易版的call
* @param {*} thisArg 需要绑定的this 这里做一个简单的边界处理
* @param {...any} args 参数
*/
Function.prototype.mycall = function (thisArg,...args) {
// 如果用户传的undefined 或 null 那么this指向window
// Object是为了包装一下 可能用户传数字啥的...(简单的边界处理)
thisArg = (thisArg == null) ? window : Object(thisArg)
// 当前的this是什么?谁调用我,我就是谁 既然是foo.mycall() this是foo
thisArg.fn = this
// 改变this的关键 thisArg是用户传进来的 老规矩 隐式绑定this
// 假设用户传进来的是{} 那么就是 {}.fn() 那this就会被隐式绑定成 {}
var res = thisArg.fn(...args)
// 删除多余的属性
delete thisArg.fn
return res
}
function foo(num1, num2) {
console.log(this)
return num1 + num2
}
var x = foo.mycall({},1,2)
console.log(x)
实现apply
/**
*
* @param {*} thisArg 需要绑定的this 这里做一个简单的边界处理
* @param {*} argArray 参数 是一个数组
* @returns
*/
Function.prototype.myapply = function (thisArg, argArray) {
// 不用判断用户传进来的是否为数组,因为...拓展运算符 不是数组会报错
// thisArg 如果传 undefined 或者 null 会指向 window
// thisArg == null 包含了 undefined 和 null
// 用Object是为了包装一下 可能用户传数字啥的...(简单的边界处理)
var thisArg = (this == null) ? window : Object(thisArg)
var fn = this
thisArg.fn = fn
var result;
// 写法1:
// if (!argArray){ // argArray是没有值(没有传参数)
// result = thisArg.fn()
// } else{ //argArray有参数
// result = thisArg.fn(...argArray)
// }
// 写法2:
// argArray = argArray ? argArray : []
// result = thisArg.fn(...argArray)
// 写法3:
argArray = argArray || []
result = thisArg.fn(...argArray)
delete thisArg.fn
return result
}
function foo(num1, num2) {
console.log(this)
return num1 + num2
}
let res = foo.apply({}, [1,2])
console.log(res)
实现bind
Function.prototype.mybind = function (thisArg, ...argArray) {
thisArg = (thisArg == null) ? window : Object(thisArg)
thisArg.fn = this
return function (...newArgs) {
var args = [...argArray,...newArgs]
return thisArg.fn(...args)
}
}
function foo(num1, num2) {
console.log(this)
return num1 + num2
}
var x = foo.mybind({},1,2)
console.log(x())
arguments的基本使用
function bar(num1, num2, num3) {
// 1.获取参数长度
console.log(arguments.length)
// 2.根据索引值获取某一个参数
console.log(arguments[0])
// 3.callee获取当前arguments所在函数 可以直接调用
console.log(arguments.callee)
// arguments.callee()
}
bar(1,23,4,5,6,7,7)
伪数组转数组的方式
function foo(num1, num2, num3) {
// 手工遍历
var newArray = [];
for (var i = 0; i < arguments.length; i++) {
newArray.push(arguments[i]);
}
var newArray1 = Array.prototype.slice.call(arguments)
var newArray2 = [].slice.call(arguments)
var newArray3 = Array.from(arguments)
var newArray4 = [...arguments]
console.log(newArray, newArray1, newArray2, newArray3, newArray4)
}
foo(1,2,3,4,5)
实现slice
Array.prototype.myslice = function (start, end) {
var start = start || 0
var end = end || end.length
var newArray = []
for (var i = start; i < end; i++) {
// 谁调用我 this就是谁
newArray.push(this[i])
}
return newArray
}
var arr = [1,2,3,4];
console.log(arr.myslice(0,3))