🍪🧁🍧

this指向&&手写call...

  • 非严格模式下
    1. 在 浏览器 环境中,全局对象是 window。
    2. 在 Node.js 环境中,全局对象是 global
      globalThis.name='martin'
  • 严格模式下
    this是undefined

函数this永远指向最后调用他的对象

改变this指向

apply和call都只是临时改变一次函数的this指向并立即执行该函数

  1. apply()
var arr=[1,10,5,8,3];
console.log(Math.max.apply(null, arr));
//第一个参数为调用函数的this指向,第二个参数必须是数组或类数组对象作为参数列表传入
//在ES6中可以用
Math.max(...arr)
  1. call()
var arr=[1,10,5,8,3];
console.log(Math.max.call(null,arr[0],arr[1],arr[2],arr[3],arr[4])); 
//与apply()不同的是this之后传入的是参数列表
  1. bind()
    函数不会立即执行,可以分多次传参
var arr=[1,10,5,8,12];
var max=Math.max.bind(null,arr[0],arr[1],arr[2],arr[3])
console.log(max(arr[4])); //12,分两次传参

手写实现

  1. call()
    call和apply的区别就是参数的传递
Function.prototype.myCall=function(){
    let context=arguments[0]
    if(context==null||context==undefined){
        context=window
    }else{
        context=Object(context)
    const args=Array.from(arguments).slice(1)
    const randomKey='_key'+Math.random()
    context[randomKey]=this
    if(!context[randomKey]){
        context={...context,[randomKey]:this}
    }
    const result=context[randomKey](...args)
    delete context[randomKey]
    return result
}}
  1. Apply()
Function.prototype.myApply=function(){
    let context=arguments[0]
    if(context==null||context==undefined){
        context=window
    }else{
        context=Object(context)//转换为对象类型,不然基本类型会转换为对象类型
    }
    let args=arguments[1]
    let randomKey=Symbol('call_key')
    context[randomKey]=this
    if(!context[randomKey]){
        context={...context,[randomKey]:this}
    }//防止挂载失败
    let result=context[randomKey](...args)
    delete context[randomKey] //删除添加的属性,不影响原对象避免每次调用都添加属性
    return result
}

为什么要在挂载之后再检查一遍呢?
因为有一些对象,比如

const obj_2 = Object.freeze({ a: 1 }); // obj 被冻结,不能添加新属性
const fn = function() { console.log('hello'); };
fn.myCall(obj_2); // hello
  1. Bind()
Function.prototype.myBind = function() {
    if (typeof this !== "function") {
        throw new TypeError("Bind must be called on a function");
    }
    const context = arguments[0];
    const args = Array.from(arguments).slice(1);
    const fn = this;//调用bind的函数
    function boundFunction(...newArgs) {
        // 如果 new 调用 boundFunction,this 应该指向新实例
        return fn.myApply(this instanceof boundFunction ? this : context, [...args, ...newArgs]);
    }
    // 维护原函数的 prototype
    boundFunction.prototype = Object.create(fn.prototype);

    return boundFunction;
};
const fn = function() { console.log('hello'); };
const obj_3 = Object.freeze({ a: 1 }); // obj 被冻结,不能添加新属性
const obj_3 = Object.create({ a: 1 });
// const fn = function() { console.log('hello'); };
fn.myBind(obj_3);
fn()//hello

或者用const isNew = typeof new.target !== 'undefined'判断是否函数被new调用
普通调用是undefined

posted @ 2025-03-17 21:10  不想吃fun  阅读(10)  评论(0)    收藏  举报