JS代码实现new,bind,call和apply

本文深入探讨JavaScript中new、bind、call与apply方法的工作原理及其实现方式,帮助开发者理解这些核心概念,并掌握如何手动实现这些功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

new

分析:

通过new方法生成实例的原理:

1、产生了一个新的实例对象。

2、通过改变this的指向继承构造函数的属性和方法。

3、继承了原型链上的属性和方法。新对象的__proto__指向构造函数的prototype。

用代码来实现:

function myNew(fun) {
        return function() {
            let obj = {
                __proto__: fun.prototype
            };
            fun.apply(obj, arguments);
            return obj
        }
    }

改进版:

function myNew() {

        var obj = new Object(),
            constructor = [].shift.call(arguments);
        obj.__proto__ = constructor.prototype;
        var ret = constructor.apply(obj, arguments);
        return typeof ret === 'object' ? ret : obj;
    };

 

bind

bind是Function中的原型方法。

它的原理:

1、改变this的指向。

2、将函数柯里化,传入参数会保存直到参数传入完毕。

代码实现:

Function.prototype.bind = function(newThis) {
    var aArgs = Array.prototype.slice.call(arguments, 1)
    var that = this
    var NoFunc = function () {}
    var resultFunc = function () {
        return that.apply(this instanceof that ? this : newThis, aArgs.concat(Array.prototype.slice.call(arguments)))
    }
    NoFunc.prototype = that.prototype 
    resultFunc.prototype = new NoFunc()
    return resultFunc
}

 

 


aArgs.concat(Array.prototype.slice.call(arguments))

表示参数拼接,curring化实现

this instanceof that ? this : newThis
这段代码的作用是判断调用func()时的执行环境;直接调用func()的时候,this指向的是全局对象;如果是通过构造函数调用的话,this指向改变。

 

NoFunc.prototype = that.prototype;
resultFunc.prototype = new NoFunc();

相当于将得到的新对象的原型指向原对象,如果直接用‘resultFunc.prototype=that.prototype’的话会使得新对象能直接修改原型链属性,造成原型链污染。  

 

MDN上的polyfill:

 
if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== 'function') { // closest thing possible to the ECMAScript 5 // internal IsCallable function throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable'); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { // this instanceof fNOP === true时,说明返回的fBound被当做new的构造函数调用 return fToBind.apply(this instanceof fNOP ? this : oThis, // 获取调用时(fBound)的传参.bind 返回的函数入参往往是这么传递的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 维护原型关系 if (this.prototype) { // Function.prototype doesn't have a prototype property fNOP.prototype = this.prototype; } // 下行的代码使fBound.prototype是fNOP的实例,因此 // 返回的fBound若作为new的构造函数,new生成的新对象作为this传入fBound,新对象的__proto__就是fNOP的实例 fBound.prototype = new fNOP(); return fBound; }; }

call和apply

call和apply的原理:

1.Call和apply中的对象调用了当前对象,this指向改变.

2.执行.

代码实现:

Function.prototype.myCall=function(toCall){
        toCall.fn=this;
        let args=[];
        let len=arguments.length;
        for(let i=0;i<len;i++){
            args.push(arguments[i])
        }
        var res=eval('toCall.fn('+args+')');
        delete toCall.fn;
        return res;
    }

原理:
1.将函数设为对象的属性
2.执行该函数
3.删除该函数

apply:

Function.prototype.apply = function (context, arr) {
    var context = Object(context) || window;
    context.fn = this;

    var result;
    if (!arr) {
        result = context.fn();
    }
    else {
        var args = [];
        for (var i = 0, len = arr.length; i < len; i++) {
            args.push('arr[' + i + ']');
        }
        result = eval('context.fn(' + args + ')')
    }

    delete context.fn
    return result;
}

外链:https://slartbartfast.cn/articlePage.php?articleid=257

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值