手撕 JavaScript 代码
new 的模拟实现
new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象类型之一
过程:
- 首先创建一个新的空对象
- 设置原型,将对象的原型(
__proto__
)设置为函数的 prototype 对象 - 让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
- 判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象
实现:
function objectFactory(){
let Constructor = Array.prototype.shift.call(arguments)
if(typeof Constructor !== 'function') {
console.err('type err')
return;
}
let obj = Object.create(Constructor.prototype)
let ret = Constructor.apply(obj, arguments)
let flag = ret && (typeof ret === "object" || typeof ret === "function")
return flag ? ret : obj
}
Array.prototype.filter
参数:一个函数参数。这个函数接受一个默认参数,就是当前元素。这个作为参数的函数返回值为一个布尔值类型,决定元素是否保留。
filter 方法返回值为一个新的数组,这个数组里面包含参数里面所有被保留的项。
示例:
let nums = [1,2,3]
let odd = nums.filter(item=>item%2) //[1,3]
实现
Array.prototype.filter = function(callback, thisArg){
// 处理数组异常情况
if(this === undefined || this === null) {
throw new TypeError('this is null or not undefined')
}
if(typeof callback !== 'function'){
throw new TypeError(callback + ' is not a function')
}
const res = []
// 让 O 成为回调函数的对象传递(强制转换对象)
let O = Object(this)
// >>>0 保证len为number, 且为正数
let len = O.length >>> 0
let resLen = 0
for(let i=0; i<len; i++){
// 检测 i 是否在O的属性中(会检查原型链)
if(i in O){
let element = O[i]
if(callback.call(thisArg, O[i], i, O)){
res[resLen++] = element
}
}
}
return res
}
关于 >>>0
,请看 js中 something >>> 0是什么意思?
Array.prototype.map
- 参数:接受两个参数,一个是回调函数,一个是回调函数的 this(可选)
- 其中,回调函数被默认传入三个值,依次为当前元素、当前索引、整个数组。
- 创建一个数组,其结果是该数组中的每个元素都调用一个提供的函数后返回的结果
- 对原来的数组没有影响。
实现
Array.prototype.map = function(callback, thisArg){
if(this === null || this === undefined){
throw new TypeError("Can not read property 'map' of null or undefined")
}
if(Object.prototype.toString.call(callback) !== '[object Function]'){
throw new TypeError(callback + ' is not a function')
}
let res = []
let O = Object(this)
let len = O.length >>> 0
for(let i=0; i<len; i++){
if(i in O){
//调用回调函数并传入新数组
res[i] = callback.call(thisArg, O[i], i, this)
}
}
return res
}
Array.prototype.forEach
与 Array.prototype.map
差不多,但没有返回值。
Array.prototype.forEach = function(callback, thisArg){
if(this === null || this === undefined){
throw new TypeError("Can not read property 'map' of null or undefined")
}
if(Object.prototype.toString.call(callback) !== '[object Function]'){
throw new TypeError(callback + ' is not a function')
}
let O = Object(this)
let len = O.length >>> 0
for(let i=0; i<len; i++){
if(i in O){
callback.call(thisArg, O[i], i, this)
}
}
}
Array.prototype.reduce
- 参数:一个为回调函数,一个为初始值。
- 回调函数中三个默认参数,依次为积累值、当前值、整个数组
- 不传默认值会自动以第一个元素为初始值,然后从第二个元素开始一次累计
示例
let nums = [1,2,3]
let newNums = nums.reduce(function(pre, cur, nums){
return pre+cur
},0) //6
实现
Array.prototype.reduce = function(callback, initialValue){
if(this === null || this === undefined){
throw new TypeError("Can not read property 'map' of null or undefined")
}
if(Object.prototype.toString.call(callback) !== '[object Function]'){
throw new TypeError(callback + ' is not a function')
}
let O = Object(this)
let len = O.length >>> 0
let k = 0
let accumulator = initialValue
// 如果第二个参数为 undefined 的情况下,数组的第一个有效值作为累加器的初始值
if(accumulator === undefined){
while(k<len && !(k in O)){
k++
}
if(k >= len){
throw new TypeError('Reduce of empty array with no initial value')
}
accumulator = O[k++]
}
while(k < len){
if(k in O){
accumulator = callback.call(undefined, accumulator, O[k], O)
}
}
return accumulator
}
call 的模拟实现
call() 方法在使用一个指定的 this 值和若干个指定的参数值的前提下调用某个函数或方法。
Function.prototype.call = function(context = window, ...args){
if(typeof this !== 'function'){
throw new TypeError('Type Error')
}
context._fn = this
let result = context._fn(...args)
delete context._fn
return result
}
apply 的模拟实现
第一个参数为绑定的this,默认为window,第二个参数是数组或类数组
Function.prototype.apply = function(context = window, args){
if(typeof this !== 'function'){
throw new TypeError('Type Error')
}
context._fn = this
let result = context._fn(...args)
delete context._fn
return result
}
bind 的模拟实现
bind() 方法会创建一个新函数。当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this,之后的一序列参数将会在传递的实参前传入作为它的参数。
【注意】:一个绑定函数也能使用new操作符创建对象:这种行为就像把原函数当成构造器。提供的 this 值被忽略,同时调用时的参数被提供给模拟函数。
Function.prototype.bind = function(context = window, ...args){
if(typeof this !== "function"){
throw new Error("Type Error")
}
// 保存 this 的值
var self = this
return function F(){
//考虑new的情况
// 当作为构造函数时,this 指向实例,此时结果为 true,将绑定函数的 this 指向该实例,可以让实例获得来自绑定函数的值
if(this instanceof F){
return new self(...args, ...arguments)
}
return self.apply(context, [...args, ...arguments])
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论