前端学习笔记--模拟call和apply以及沙盒模型

本文介绍了JavaScript中的模拟call和apply方法,以及如何使用代理和快照沙盒来避免函数作用域冲突。通过实例展示了如何在不同的沙盒环境中控制函数的执行效果。

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

模拟call
  • 第一个参数为null或者undefined时,this指向全局对象window,值为原始值的指向该原始值的自动包装对象,如 StringNumberBoolean
  • 为了避免函数名与上下文(context)的属性发生冲突,使用Symbol类型作为唯一值
  • 将函数作为传入的上下文(context)属性执行
  • 函数执行完成后删除该属性
  • 返回执行结果
Function.prototype.myCall = function (context, ...args) {
    context = (context ?? window) || new Object(context)
    const key = Symbol()
    context[key] = this
    const result = context[key](...args)
    delete context[key]
    return result
}
function myfunc1() {
    this.name = 'Lee';
    this.myTxt = function (txt) {
        console.log('i am', txt);
    }
}
function myfunc2() {
    myfunc1.myCall(this);
}
var myfunc2Instance = new myfunc2();
console.log(myfunc2Instance);
myfunc2Instance.myTxt('Geing'); // i am Geing
console.log(myfunc2Instance.name);	// Lee

注:ES2020新特性,Null判断符 ??

模拟apply
  • 前部分与call一样
  • 第二个参数可以不传,但类型必须为数组或者类数组
Function.prototype.myApply = function (context) {
    context = (context ?? window) || new Object(context);
    const key = Symbol();
    const args = arguments[1];
    context[key] = this;
    let result;
    if (args) {
        result = context[key](...args);
    } else {
        result = context[key]();
    }
    return result;
}
function myfunc1() {
    this.name = 'Lee';
    this.myTxt = function (txt) {
        console.log('i am', txt);
    }
}
function myfunc2() {
    myfunc1.myApply(this);
}
var myfunc2Instance = new myfunc2();
console.log(myfunc2Instance);
myfunc2Instance.myTxt('Geing'); // i am Geing
console.log(myfunc2Instance.name);	// Lee

注:代码实现存在缺陷,当第二个参数为类数组时,未作判断

沙盒模型
1.代理沙盒
window = global
function proxySanbox() {
    const originalWindow = window;
    this.fackWindow = {}
    this.proxy = new Proxy(this.fackWindow, {
        set(target, p, value) {
            target[p] = value;
            return true;
        },
        get(target, p) {
            return target[p] || originalWindow[p];
        }
    })
}
const sanbox1 = new proxySanbox();
const sanbox2 = new proxySanbox();
window.a = 'a in window';
console.log(window.a);//a in window
((window) => {
    window.a = 'a in sanbox1';
    console.log(window.a);//a in sanbox1
})(sanbox1.proxy);
((window) => {
    window.a = 'a in sanbox2';
    console.log(window.a);//a in sanbox2
})(sanbox2.proxy);
console.log(window.a);//a in window
2.快照沙盒
window = global
class snapshotSanbox {
    constructor() {
        this.snapshot = {}
        this.modifyProps = {};
    }
    active() {
        for (const prop in window) {
            if (window.hasOwnProperty(prop)) {
                this.snapshot[prop] = window[prop];
            }
        }
        Object.keys(this.modifyProps).forEach((prop) => {
            window[prop] = this.modifyProps[prop]
        })
    }
    inActive() {
        for (const prop in window) {
            if (window.hasOwnProperty(prop)) {
                if (window[prop] !== this.snapshot[prop]) {
                    this.modifyProps[prop] = window[prop];
                    window[prop] = this.snapshot[prop];
                }
            }
        }
    }
}
const sanbox1 = new snapshotSanbox();
const sanbox2 = new snapshotSanbox();
window.a = 'a in window';
console.log(window.a); //a in window
sanbox1.active()
window.a = 'a in sanbox1';
console.log(window.a);//a in sanbox1
sanbox1.inActive()
console.log(window.a);//a in window
sanbox2.active()
window.a = 'a in sanbox2';
console.log(window.a);//a in sanbox2
sanbox2.inActive()
console.log(window.a);//a in window
sanbox1.active()
console.log(window.a);//a in sanbox1
sanbox2.active()
console.log(window.a);//a in sanbox2
sanbox2.inActive()
console.log(window.a);//a in sanbox1
sanbox1.inActive()
console.log(window.a);//a in window
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

onnx

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值