遇事不决看源码

简介

手撕常用源码为面试中必备的技能,欢迎各位大佬一起探讨指正~

实现一个new源码

首先了解new对实例化构造函数时内部实现了啥:

  1. 创建一个控对象
  2. 将构造函数的原型对象添加到这个对象的隐形属性__proto__
  3. 执行构造函数当函数返回对象的时候,返回对象
  4. 当函数返回非对象的时候返回这个ob j

具体代码实现逻辑如下

// es5写法
function newp(Con,...args){
	const obj = Object.create(Con.prototype);
	const res = Con.apply(obj, args)
	return res instanceof Object ? res : obj
}
// es3
function newP(){
	const obj = new Object();
	const args = Array.prototype.slice.call(arguments, 1);
	const Con = Array.prototype.shift.call(arguments);
	obj.__proto__ = Con.prototype;
	const res = Con.apply(obj, args);
	return res instanceof Object ? res : obj;
}

实现Object.create

上面new的例子在es5的写法中用到了Object.create的写法,因此我们了解到Object.create的作用是创建一个新对象,使用现有的对象作为新创建对象的prototype。:

  1. 先生成一个空对象
  2. 将传入的对象添加到这个对象的隐形属性__proto__中
  3. 最后的生成的对象的原型对象的constructor属性要指向创建的对象

具体代码实现逻辑如下

function create(object){
	const obj = new Object();
	obj.__prototype = object;
	obj.__prototype.constructor = obj;
	return obj
}

实现instanceof

学习过原型链的都知道判断一个对象是否在某个原型链上,以及判别引用类型的方法不能用typeof, 而是instanceof 那么手撕一波:

// 1. 检测构造函数的 prototype 属性是否出现在某个实例对象的原型链
// 2. Object.getPrototypeOf(obj(要返回其原型的对象)) 方法返回指定对象的原型(内部[[Prototype]]属性的值)。
// 3. 返回值:给定对象的原型。L.__proto__.__proto__ 直到 proto 为 null,则返回 null 。
// 4. 函数中的while(true){return} 不会无限循环,当出发return结束循环
function instanceofP(L, R){
	if(typeof(L) !== 'object'){
	  return false
  }
  let l = L.getPrototypeOf(L);
  const r = R.prototype;
  while(l !== null){
	if(l === r){
		return true
	}
	l = l.getPrototypeOf(l)
  }
}

bind实现

bind做了啥

  1. bind是Function原型链中的Function.prototype的一个属性,
  2. 它是一个函数,修改this指向,合并参数传递给原函数,返回值是一个新的函数。
  3. bind返回的函数, 可以通过new调用,返回原函数的实例,但是不改变this指向
  4. 指向了new生成的全新对象。内部模拟实现了new操作符。
/* eslint-disable no-extend-native */
Function.prototype.bind3 = function () {
  if (!(this instanceof Function)) {
    throw new Error('is not a function');
  }
  const func = this;
  const args = Array.prototype.slice.call(arguments, 1);
  const Content = Array.prototype.shift.call(arguments);

  return function F() {
    const argp = Array.prototype.slice.call(arguments);
    const Arg = args.concat(argp);
    const selfp = this;
    // this instanceof f   正常情况下这种情况返回的是纯粹函数,this指向的是全局当用new时this指向的时F, 否则指向的原来的构造函数的原型对象
    if (selfp.__proto__ === F.prototype) {
      return new func(...Arg);
    }
    return func.apply(Content, Arg);
  };
};

call实现

call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。这是也是利用函数this指向对象的套路同apply

// 参数你也可以指定(self, ... agrs)我这里用arguments只是单纯为了装b
Function.prototype.callp = function () {
  // 这里还是我想玩一下原型链的骚操作
  // 可以用!(this.instanceof Function),或者typeof(this) === 'function
  if (this.__proto__ !== Function.prototype) {
    throw new Error('is not function');
  }
  const args = Array.prototype.slice.call(arguments, 1);
  const content = this;
  // 为什么用shift, 问就是为了装b
  const self = Array.prototype.shift.call(arguments) || {};
  self.fuc = content;
  const res = self.fuc(...args);
  // 这里一定要记的删掉this中添加的函数属性
  delete self.fuc;
  return res;
};

apply实现

apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)提供的参数, 返回修改this指向的函数结果, 利用this指向(obj)特性实现apply源码

/* eslint-disable no-extend-native */
// apply改变函数this指向, 返回改变指向的函数的结果
Function.prototype.applyp = function (self, args) {
  if (!(this instanceof Function)) {
    throw new Error('is not function');
  }
  const content = this;
  const selfp = self || {};
  selfp.content = content;
  const res = self.content(...args);
  // 一定要将添加到修改函数this指向中的函数去掉
  delete self.content;
  return res;
};

结束语

如果各位大佬觉得还不错请给个素质3连,欢迎各位大佬提出更好的写法~

<think>嗯,用户想解DatePicker失去焦点后内容未被清空的问题。首先,我需要明确问题具体情况。用户提到的是在失去焦点后内容未被清空,但可能实际需求是希望即使失去焦点,已选择的内容仍然保留,而是被清空。这可能是因为某些情况下,组件在失去焦点时会触发校验或者默认行为导致内容被重置。 接下来,我需要参考之前提供的引用内容。引用[1]提到Vue3和Element Plus的DatePicker在清空或选中时触发多次change事件的问题,这可能与事件处理有关。引用[3]提到组件自己处理状态,如表单校验时传递state给各个组件。这可能意味着需要控制组件的状态更新时机,避免外部因素干扰。 首先,可能的原因之一是组件的blur事件触发了某些重置逻辑。例如,当用户选择日期后,离开输入框时,组件可能根据表单的校验状态或其他逻辑重置内容。或者,组件本身在失去焦点时如果没有合法值,会自动清空内容。 解方案可能包括: 1. 禁用blur事件中的自动清空逻辑。可能需要查看Element Plus的文档,是否有相关的配置项来控制失去焦点时的行为。例如,是否有属性可以设置为自动清空。 2. 使用受控组件的方式,将选中的值绑定到组件的v-model,并确保在外部状态变化时会意外重置。例如,在Vue中,确保v-model绑定的值会被父组件错误地修改。 3. 在blur事件中手动处理值,如果发现值为空,则阻止清空操作,或者重新赋值之前的值。这可能需要监听blur事件,并在事件处理函数中进行判断和干预。 4. 检查是否有其他事件监听器干扰,例如change事件被多次触发,导致状态一致。引用[1]中提到change事件触发两次的问题,可能需要类似的方法,比如使用防抖或者标记位来确保只处理一次。 另外,引用[3]中提到组件自己管理状态,可能需要确保表单的校验会在失去焦点时强制清空内容。例如,在校验失败时,保持用户输入的值而是清空。 可能的实现步骤: - 确认组件的绑定值是否正确,确保父组件没有在应该的时候重置该值。 - 检查是否有在blur事件中触发的逻辑,例如表单校验,导致值被重置。 - 使用v-model绑定日期值,并在失去焦点时手动处理,例如在blur事件中检查并维持当前值。 - 可能需要使用:value和@input来手动控制值的更新,而是使用v-model,从而更精细地控制行为。 另外,可能需要查阅Element Plus的官方文档或社区讨论,看看是否有其他开发者遇到类似问题,以及官方推荐的解方案。例如,是否有属性如clearable或是否在特定情况下需要阻止默认行为。 例如,在Element Plus的DatePicker中,可能有一个属性可以配置是否在失去焦点时清空内容,或者需要结合@blur事件来维持当前值。如果组件本身没有提供这样的配置,可能需要通过监听事件并手动维护值来解。 总结可能的解方案: 1. 确保v-model正确绑定,避免父组件意外修改。 2. 在blur事件中手动维持当前值,例如通过$event.target.value获取并重新赋值。 3. 使用表单校验的控制,确保校验导致值清空。 4. 检查是否有其他事件干扰,如多次触发change事件,需要防抖或条件判断。 需要验证这些思路,并提供具体的代码示例,比如在Vue中如何处理blur事件,或者在Element Plus中设置相关属性。</think>针对DatePicker组件失去焦点后内容被清空的问题,可通过以下方案解: ### 解方案(以Element Plus为例) 1. **双向绑定控制** 使用`v-model`绑定值时,需确保父组件会主动重置该值: ```vue <template> <el-date-picker v-model="dateValue" @blur="handleBlur" :clearable="false" /> </template> <script setup> import { ref } from 'vue' const dateValue = ref('') const handleBlur = () => { if (!dateValue.value) { dateValue.value = '' // 手动控制空值逻辑 } } </script> ``` 2. **禁用自动清空** 通过`clearable`属性关闭清空按钮,减少误触: ```vue <el-date-picker :clearable="false" /> ``` 3. **状态管理拦截** 通过`@blur`事件拦截非法清空行为: ```vue <el-date-picker v-model="dateValue" @blur="(e) => e.target.value = dateValue || ''" /> ``` ### 问题根源 组件默认会在失去焦点时触发校验逻辑,若输入内容未通过校验(如格式错误),部分UI库会自动重置值[^3]。通过受控状态管理可阻断此行为。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值