金色小芝麻

vuePress-theme-reco 金色小芝麻    2021 - 2023
金色小芝麻 金色小芝麻

Choose mode

  • dark
  • auto
  • light
主页
分类
  • JavaScript
  • BUG复盘
  • SVG笔记
  • TypeScript
  • 个人总结
  • CSS笔记
  • 开发工具
  • 前端入门
  • Vue2.0
  • 性能优化
  • 架构学习
  • 每日一题
标签
时间轴
社交
  • 掘金 (opens new window)
author-avatar

金色小芝麻

83

文章

27

标签

主页
分类
  • JavaScript
  • BUG复盘
  • SVG笔记
  • TypeScript
  • 个人总结
  • CSS笔记
  • 开发工具
  • 前端入门
  • Vue2.0
  • 性能优化
  • 架构学习
  • 每日一题
标签
时间轴
社交
  • 掘金 (opens new window)
  • 前端入门

    • 博客搭建过程及相关配置
    • 数组中的16种常用方法
    • JS中的数据类型简析——基本数据类型值
    • JS中的数据类型object基础
    • JS中三种常见的判断
    • 数据类型之间的区别(堆内存Heap VS 栈内存Stack)
    • JS基础练习题及解析
    • 开关灯的小案例
    • JS中数据类型检测方法——typeof
    • 条件判断几个小练习
    • JS循环——for循环
    • 自定义属性实现选项卡小案例
    • 字符串中的12种常用方法
    • DOM操作的简单原理
    • JS实现隔行变色鼠标跟随小案例
    • JS中function的基础知识
    • JS中数组去重的三种方法
    • JS中时间格式化的三种方法
    • JS中URL参数处理的三种方法
    • JS小案例——获取随机验证码
    • DOM操作之——获取DOM标签的9种方式
    • DOM操作之——DOM节点类型及属性
    • DOM操作之——元素的增删改、样式修改、插入内容
    • JS中THIS相关问题梳理
    • JS中的变量提升机制
    • 在全局:私有上下文中:带VAR和不带VAR的区别
    • 作用域和作用域链查找机制
    • JS中堆栈内存的释放问题
    • JS中的闭包机制
    • ES3和ES6定义变量的区别
    • JS中的单例和工厂设计模式
    • JS中的面向对象OOP理论基础
    • 构造函数创建自定义类
    • JS中的原型和原型链
    • Math中常用的9种方法
    • 从一道阿里经典面试题剖析函数三种角色
    • 重写内置call
    • 重写一个内置new
    • 浏览器渲染页面的主体流程
    • 减少DOM的回流和重绘
    • JS中的多种继承方式
    • JS中数据类型检测四种方式的优缺点
    • JS中的正则表达式&&全面梳理
    • 非严格模式 🆚 严格模式的区别
    • 数组方法reduce、filter、flat
    • 获取数组中最大值/最小值的三种基础方法
    • 轮播图——渐隐渐显版
    • 深克隆 VS 浅克隆|深比较 VS 浅比较|回调函数
    • 轮播图——左右切换版
    • 事件及事件绑定、事件对象及事件传播
    • 从在地址栏输入网址到看到页面的过程&&AJAX基础
    • 想自学JS吗?想提升JS底层原理吗?76张脑图带你彻底搞懂原生JS
    • 面试手写API系列
    • 30张脑图带你从零开始学VUE
    • JS中的盒子模型
    • 初识JS-基础中的基础
    • 前端发展简史
    • JS中的三大类输出方式

重写内置call

vuePress-theme-reco 金色小芝麻    2021 - 2023

重写内置call

金色小芝麻 2020-06-08

关于call笔者之前在JS中THIS相关问题梳理 (opens new window)这篇文章中已经讲过,但笔者觉得之前写的call方法不够惊艳😺,还有很多问题没有考虑到,这次重新整理一下,希望对您有帮助;

let func = function (x, y) {
  console.log(this);
  return x + y;
};
window.name = "HELLO~";
let obj = {
  name: '小芝麻'
};

func(10, 20); //=>this:window  'HELLO~' 30
obj.func(10, 20); //=>Uncaught TypeError: obj.func is not a function

# 需求:让func执行,需要让方法中的this变为obj(func和obj本身还没啥关联)

// 实现思路:让func和obj关联在一起
// 1.给obj设置一个属性$func,让其属性值是函数func
// 2.obj.$func() 相当于把func执行了,此时方法中的this就是obj
// 3.这种操作方式会存在一些安全隐患:如果原有obj对象中就有$func的属性,我们设置的这个属性会覆盖原有的属性值[真实操作中,我们尽可能保证这个属性名的唯一性];我们设置的属性,在用完后,还要把它移除掉,因为人家对象原本是没有这个属性的;
// obj.$func = func;
// obj.$func(10, 20); //=>this:obj  '小芝麻' 30
// delete obj.$func;
// console.log(obj);

# 代码实现

// 为了让每一个函数都可以调取这个方法了
Function.prototype.changeThis = function changeThis(context, ...args) {
  // THIS:当前要执行并且改变THIS指向的函数
  // CONTEXT特殊情况的处理:不传递是window,传递null/undefined也让其是window,传递非对象或者函数类型值,我们需要让其变为对象或者函数
  context == null ? context = window : null;
  
  //=> 为了过滤出传入参数是基本类型的情况
  if (typeof context !== "object" && typeof context !== "function") {
    //=> 运用构造函数常见一个基本数据类型的实例;
    //=> 目的是为了在下面context[uniqueKey] 时,由于基本数据类型不能运用对象的“点”或者“[]”存储属性时报错的问题
    context = new context.constructor(context);
  }

  //=> 利用模版字符串和时间戳生成一个唯一的属性名
  let uniqueKey = `?${new Date().getTime()}`;
  
  //=> 给参数中新增个uniqueKey属性与调用的函数关联
  context[uniqueKey] = this;
  
  //=> 让调用的函数执行
  let result = context[uniqueKey](...args);
  
  //=> 删除新增的属性
  delete context[uniqueKey];
  
  //=> 把函数执行的结果 return 出去
  return result;
};

let result = func.changeThis(obj, 10, 20);
let result = func.changeThis();
let result = func.changeThis(null/undefined);
let result = func.changeThis(10, 20); //=>方法执行,方法中的THIS是10,给方法传递了20(第一个参数是我们要改变的THIS指向问题)

# 去除注释后的完整代码

Function.prototype.changeThis = function changeThis(context, ...args) {
  context == null ? context = window : null;
  if (typeof context !== "object" && typeof context !== "function") {
    context = new context.constructor(context);
  }
  let uniqueKey = `?${new Date().getTime()}`;
  context[uniqueKey] = this;
  let result = context[uniqueKey](...args);
  delete context[uniqueKey];
  return result;
};

let result = func.changeThis(obj, 10, 20);
let result = func.changeThis();
let result = func.changeThis(null/undefined);
let result = func.changeThis(10, 20); //=>方法执行,方法中的THIS是10,给方法传递了20(第一个参数是我们要改变的THIS指向问题)

欢迎来到 金色小芝麻
看板娘