自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(44)
  • 资源 (2)
  • 收藏
  • 关注

原创 JavaScript对象属性可枚举性详解

可枚举性在 JavaScript 中是一个重要的概念,它影响着属性的遍历和序列化行为。通过合理地设置属性的可枚举性,可以更好地控制对象的行为,使其更符合实际需求。在 JavaScript 中,对象的属性分为可枚举和不可枚举两种,这涉及到对象属性遍历、序列化等方面的行为。大多数对象的属性默认是可枚举的,但也有例外,如原型链上的属性默认是不可枚举的。不会被遍历到,更适合存储一些内部使用的属性,避免意外的外部访问和修改。不可枚举属性是指无法通过对象的属性遍历方法访问到的属性。这两者只会枚举可枚举的属性。

2024-04-19 11:22:30 717

原创 JavaScript之异步编程详解(二)

ta是实现异步编程的核心,负责管理和调度 JavaScript 代码中的任务执行顺序,确保在单线程的环境下能够处理并发的任务。由于只有一个线程,所以一次只能执行一个任务,如果某个任务阻塞了主线程,那么其他任务就无法执行,会导致页面失去响应。在 Event Loop 的执行过程中,首先执行所有的微任务,然后再执行宏任务。通过调用栈、任务队列和微任务队列的协作,保证了代码的执行顺序和协调了异步任务的回调函数。执行微任务:执行所有微任务队列中的任务,直到微任务队列为空。微任务会在当前宏任务执行结束后立即执行。

2024-04-18 09:00:44 406

原创 JavaScript之异步编程详解(一)

以上是实现异步编程的四种常见方式:回调函数、Promise、async/await和Generator。通过将一个函数作为参数传递给另一个函数,在异步任务完成后调用该函数来处理结果。async/await是ES8引入的一种基于Promise的异步编程方式,它使用起来更加简洁明了。Promise是ES6引入的一种更为优雅的异步编程方式。分享3:AI资料大全,仅分享,不做购买推荐,有需要的自行获取(回复 AI)。容易造成回调地狱,即多层嵌套的回调函数,难以维护和扩展。可以实现暂停和恢复执行的功能,灵活性较高。

2024-04-17 09:05:06 1180

原创 JavaScript之函数详解

今天说一下绍构造函数、普通函数、匿名函数、箭头函数、类及类中定义的方法、以及自执行函数。今天分享,AI资料大全,仅分享,不做购买推荐,有需要的自行获取(回复 AI)。优点:确保方法内部的 this 指向,避免因为函数嵌套导致的 this。箭头函数是 ES6 引入的新语法,具有更简洁的语法和固定的。优点:可以通过构造函数初始化对象,实现对象的复用。简单的函数定义,尤其在需要固定 this 指向时。缺点:无法作为构造函数使用,没有自己的 this。作为某些函数的参数,或者在需要时即时定义和执行。

2024-04-16 09:04:44 501

原创 JavaScript之Proxy详解

是JavaScript中的一个强大而灵活的特性,它允许你创建一个代理对象,可以拦截并改变对象的底层操作。是ES6引入的一个新对象,用于创建一个对象的代理,可以拦截并重定义基本的操作。提供了丰富的拦截操作,使得我们能够对对象的行为进行灵活的定制。可以实现对象属性的懒加载,只在访问时才进行实际的计算或获取。能够实现更清晰和易读的代码,避免了传统的一些hack手段。的特性和应用场景,有助于更好地利用它提供的强大功能。是ES6引入的特性,不支持ES6的环境无法使用。可以实现数据绑定,监听对象属性的变化。

2024-04-15 09:12:52 429

原创 JavaScript流文件下载实现详解

今天分享,有需要的自行获取(回复 11)。前端web、h5实现方式。

2024-04-14 16:44:27 593

原创 JavaScript中的Blob、Buffer、ArrayBuffer和TypedArray详解

摘要:本文详细介绍了JavaScript中的Blob、Buffer、ArrayBuffer和TypedArray,这些类型和API在处理二进制数据时非常有用。综上所述,Blob适用于处理文件和媒体内容,Buffer适用于Node.js环境下的二进制数据处理,ArrayBuffer和TypedArray适用于通用的二进制数据操作。TypedArray可以直接读取和写入ArrayBuffer中的数据,并提供了一些额外的方法和属性。ArrayBuffer是一种用于表示通用的固定长度的二进制数据缓冲区的类型。

2024-04-13 14:40:23 383

原创 JavaScript之Object.defineProperty详解

它允许我们精确地控制对象属性的特性,包括可枚举性、可写性、可配置性等。描述符对象是一个普通的 JavaScript 对象,它有一些可选的键值对,用于定义属性的特性。当需要定义一些特殊属性,比如不可写、不可配置、不可枚举等时,可以使用该方法。当需要对属性进行精确的特性定制时,比如定义计算属性、阻止属性被遍历等。允许我们精确地控制属性的各种特性,包括可写性、可枚举性、可配置性等。可以通过设定属性为不可写、不可配置,防止对属性的误操作。:属性的描述符对象,包含属性的特性。:要定义或修改的属性的名称。

2024-04-12 09:11:28 322

原创 JavaScript处理异步循环的技术详解

当需要按照顺序执行异步任务,且任务之间有依赖关系时,使用async/await结合Promise是一个强大的选择。在异步循环中,要考虑适当的错误处理机制,以确保能够捕获和处理每个异步任务可能抛出的异常。当需要按照特定顺序执行异步任务,且任务之间有依赖关系时,递归是一个清晰的解决方案。在大规模数据的情况下,可以考虑分批处理数据,以避免同时处理大量异步任务导致性能下降。并行执行异步任务,提高性能,适用于任务之间相互独立的场景。考虑循环的性质和异步任务之间的关系,选择适当的处理方式。

2024-04-11 09:09:14 1142

原创 JavaScript异步操作详解

这些都是常见的异步编程方式,选择其中之一取决于项目的要求和个人偏好。在现代JavaScript中,Promise和async/await是更常用的选择,因为它们提供了更清晰、可读性更好的代码结构。异步操作允许在执行其他任务的同时执行耗时操作,当任务完成时,通过回调函数、Promise、async/await或事件监听来处理结果。async/await是ES2017引入的语法糖,使异步代码看起来更像同步代码,更易于理解。JavaScript中的异步操作,通常指的是那些不会阻塞代码执行的操作。

2024-04-10 09:14:21 488

原创 JavaScript中如何理解堆栈溢出和内存泄漏

在 JavaScript 中,内存泄漏通常是因为对不再需要的对象仍然存在引用,使得这些对象不能被垃圾回收。JavaScript 引擎使用调用栈来追踪函数的调用关系,堆栈溢出是指当递归调用或函数调用过多层次时,JavaScript引擎的调用栈空间耗尽,导致程序崩溃。如果该元素在后续操作中被删除,这个匿名函数依然存在,导致元素引用不被释放,从而发生内存泄漏。在JavaScript中,堆栈溢出和内存泄漏是两种常见的内存管理问题,它们可能导致程序性能下降、崩溃或其他不稳定的行为。使用递归时确保有终止条件。

2024-04-09 09:05:31 539

原创 JavaScript之作用域链详解

作用域链是由变量对象的列表组成,这些变量对象按照它们被创建的顺序排列。本文将详细介绍JavaScript作用域链,包括什么是作用域链、作用域链的创建过程、作用域链的查找规则以及相关的代码示例。通过深入了解作用域链的创建过程和查找规则,我们能更好地理解JavaScript代码的执行过程,尤其是在涉及嵌套函数和闭包的情况下。:作用域链的顶端是当前执行上下文的变量对象,然后依次链接到父级执行上下文的变量对象,直至全局执行上下文。闭包是指在一个函数内部定义的函数,它可以访问外部函数的变量,形成一个闭包作用域链。

2024-04-07 20:59:33 481

原创 JavaScript之闭包的实现原理和作用详解

这个内部函数可以访问外部函数的变量,因为它维持了对外部函数变量对象的引用。闭包是JavaScript中强大而灵活的概念,它不仅可以解决作用域的问题,还能够实现函数式编程的一些特性。本文将详细解释JavaScript闭包的实现原理和作用,包括什么是闭包、闭包的实现原理、闭包的作用以及具体的代码示例。闭包是JavaScript中一项强大的特性,它通过保留外部函数的变量对象,使得内部函数可以访问和操作外部函数的变量。是指在一个函数内部定义的函数,并且这个内部函数可以访问外部函数的变量。2. 闭包的实现原理。

2024-04-06 10:46:10 226

原创 JavaScript之this详解

的不同绑定规则是编写高质量JavaScript代码的重要一步。通过掌握这些规则,可以更好地设计和组织代码,确保。的不同绑定规则,包括默认绑定、隐式绑定、显式绑定、new 绑定以及箭头函数中的。是一个关键字,表示当前执行代码的上下文。的指向可能会出现问题,特别是在异步操作或事件处理中。箭头函数继承自最近的外围非箭头函数作用域的。在全局作用域中或函数内部,当没有明确指定。方法,可以显式指定函数执行时的。的值可能会丢失或产生意外的结果。当函数作为对象的方法被调用时,指向调用该方法的对象。**:在回调函数中,

2024-04-05 10:46:32 189

原创 JavaScript之applye、bind和call方法详解

apply()、bind()和call()方法的作用都是改变this指向,可以指定该函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。apply()和call()立即执行,bind()返回新函数,并非立即执行。Q1 apply()、bind()和call()方法的区别在哪?Q3 apply()、bind()和call()方法手写实现逻辑。Q2 apply()和call()的应用场景。将数组的空元素变为undefined。apply()的参数为数组。

2024-04-04 17:17:31 624

原创 JavaScript变量对象详解

JavaScript中的变量对象是理解作用域、作用域链和变量声明提升的关键概念之一。通过了解变量对象的结构、创建过程和与作用域链的关系,我们能更好地理解JavaScript代码的执行过程。在JavaScript中,变量对象是执行上下文中的一个重要概念,它负责存储函数中的变量、函数声明和形参。变量对象是在执行上下文创建阶段被创建的,用于存储该上下文中的变量、函数声明和形参。不同类型的上下文(全局上下文、函数上下文)有不同的变量对象。作用域链是由当前执行上下文的变量对象和其父级执行上下文的变量对象组成的。

2024-04-03 09:02:25 574

原创 JavaScript执行上下文详解

每当执行一段可执行代码(例如函数、全局代码)时,就会进入一个新的执行上下文。执行上下文是JavaScript中一个关键的概念,它定义了代码在运行时的环境和范围。了解执行上下文对于理解变量的作用域、作用域链以及代码的执行顺序至关重要。全局执行上下文是默认的、最外层的执行上下文。每当调用一个函数时,都会创建一个新的函数执行上下文。函数执行的代码会在一个新的执行上下文中运行,被称为Eval执行上下文。函数执行时,会创建函数执行上下文,其中包括全局变量和局部变量。:在函数上下文中,执行函数体内的代码。

2024-04-02 13:25:16 338

原创 JavaScript作用域详解

JavaScript 的作用域(Scope)是指在代码中定义变量时,这些变量在哪里以及在哪些地方可以被访问。在 JavaScript 中,有全局作用域和局部作用域的概念,作用域的规则由函数定义和代码块定义来决定。词法作用域是指变量的作用域在代码写好的时候就确定了,而不是在运行时确定。作用域是 JavaScript 中重要的概念,理解作用域有助于正确使用变量、避免命名冲突,提高代码的可维护性。作用域可分为词法作用域和动态作用域,JavaScript 使用词法作用域,也称为静态作用域。

2024-04-01 17:29:38 250

原创 JavaScript作用域的定义、原理及示例

词法作用域是指在代码编写的时候就确定了变量和函数的作用域,动态作用域是指在函数调用的时候才确定变量和函数的作用域。在词法作用域中, foo() 应该在自己的作用域中查找变量 bar,但是在动态作用域中,它会在调用它的函数 baz() 的作用域中查找变量 bar,所以它可以访问到 baz() 中的变量 bar。动态作用域的原理是在函数调用时,会将当前作用域压入一个作用域栈中,然后在函数内部查找变量时,会先从栈顶查找,如果找不到,就会继续向下查找,直到找到为止。

2024-04-01 17:10:35 264

原创 JavaScript之Class构造及继承的底层实现原理

其实现在也有这种担心,所以每篇文章都是用心完成,但也不敢完全保障没有失误的地方,如果有朋友发现,还请留言指出,我们也可以进行技术讨论。然而,在底层,JavaScript 仍然是基于原型的语言,class 只是一种更便捷的语法,其实现仍然依赖于原型继承。底层实现中,class 声明的类被转化为一个函数,构造函数的逻辑被放在了这个函数的 constructor 方法中,而类的方法则被添加到该函数的原型上。每个通过类创建的实例都拥有一个原型链,该原型链连接着该实例的原型和父类的原型。

2024-03-30 09:30:19 401

原创 JavaScript new一个对象的详细过程

JavaScript new一个对象的详细过程 new实现过程 new实现原理 new手写实现。最后返回this指向的新对象(如果是引用类型则返回引用类型,否则返回Objective)给空对象添加__proto__属性。执行构造函数对这个空对象进行构造。开辟一块内存,创建一个空对象。调用函数改变this指向。

2024-03-29 12:31:33 542

原创 JavaScript中的继承方式详解

组合继承结合了原型链继承和构造函数继承,通过调用父类构造函数设置实例属性,再通过将父类实例作为子类原型来实现。原型式继承通过创建一个空对象,然后将该对象作为参数传递给一个函数,该函数的原型被赋值为这个对象,从而实现继承。原型链继承是通过将子类的原型设置为父类的实例来实现继承。包含原型链继承、构造函数继承、组合继承、原型式继承、寄生式继承、寄生组合式继承和ES6 类继承。寄生式继承在原型式继承的基础上,增加了对父类构造函数的调用,从而可以传递参数给父类构造函数。解决了原型链继承中引用类型属性共享的问题。

2024-03-28 09:02:31 589

原创 JavaScript原型、原型对象、原型链系列详解(五)

同时,JavaScript原型设计模式还可以提高代码的可维护性和可扩展性,通过继承和复用原型对象的属性和方法,可以让代码更加灵活和易于扩展。JavaScript中的每个对象都有一个原型对象,通过将对象的属性和方法定义在原型对象上,可以让多个对象共享同一个原型对象,从而实现对象之间的继承和复用。基于构造函数和原型对象的实现方法:这种实现方法是JavaScript原型设计模式的经典实现方式,通过定义一个构造函数和一个原型对象,并将构造函数的prototype属性指向原型对象,就可以实现对象之间的继承和复用。

2024-03-27 09:03:11 419

原创 JavaScript原型、原型对象、原型链系列详解(四)

在访问 john 对象的属性时,它会先查找自身是否有该属性,然后会沿着原型链查找 Person.prototype 对象,最终查找到了 Object.prototype 对象。原型链是原型对象之间的连接,每个原型对象都有一个指向父级原型对象的指针,即Prototype属性。原型是函数的一个属性,它指向原型对象的引用。JavaScript中的原型、原型对象和原型链是密不可分的概念,它们之间构成了对象继承的基础。当我们创建一个子类时,它的原型对象指向父类的实例,从而实现了父类的属性和方法的继承。

2024-03-26 09:05:08 880

原创 JavaScript原型、原型对象、原型链系列详解(三)

因此,当我们调用 person.sayHello() 方法时,JavaScript 引擎会首先查找 person 对象本身是否有 sayHello 方法,如果没有,就会去它的原型对象 Person.prototype 上查找,如果还没有,就会去 Person.prototype 的原型对象 Object.prototype 上查找,以此类推,直到找到为止。这个链接的作用是如果对象本身没有某个属性或方法,就会去它的原型对象上找,如果还没有,就会去原型对象的原型对象上找,以此类推,直到找到为止。

2024-03-25 09:48:00 1119

原创 JavaScript原型、原型对象、原型链系列详解(二)

当我们调用 person 对象的 sayHello 方法时,JavaScript 首先会查找该对象本身是否具有该方法,由于 person 对象本身并没有该方法,因此 JavaScript 会查找 person 对象的 proto 属性指向的原型对象中是否具有该方法,如果有,就会调用该方法。当我们使用 Object 构造函数创建一个新的对象时,JavaScript 会自动为该对象创建一个原型对象,该原型对象会包含一些基本的属性和方法,例如 toString()、valueOf() 等。

2024-03-24 11:09:08 300

原创 JavaScript原型、原型对象、原型链系列详解(一)

当我们访问一个对象的属性或方法时,JavaScript 会先在该对象本身中查找,如果找不到,就会到该对象的原型对象中查找。如果找不到,就会返回 undefined。其中,Person 构造函数的原型对象包含了 name 和 sayHello 属性和方法,而 cat 对象是一个普通对象,它的原型对象是 Object.prototype。JavaScript 的原型机制在面向对象编程中发挥了重要的作用,它允许我们创建一个类或者对象的模板,然后通过继承来创建新的对象,从而大大减少了重复编写代码的工作量。

2024-03-23 12:13:28 874

原创 飞跃前端瓶颈:技术进阶指南精华篇

在互联网的快车道上,前端技术日新月异。书籍能够提供系统的知识结构和行业洞察,构建全面的知识体系,提升深度和广度。熟练掌握HTML、CSS、JavaScript基础,了解页面布局和响应式设计,熟悉至少一种主流前端框架。精通前端技术,关注性能优化和架构设计,具备团队管理和项目领导能力。深入研究前端技术,推动技术创新,具备丰富的项目管理和团队领导经验。对前端技术有深入理解,具备实战经验,了解前后端分离和构建工具。通过实际项目提升技术能力,参与开源项目,为社区贡献。针对技术短板,深入学习基础知识和新技术。

2024-03-21 21:42:30 464

原创 JavaScript小数运算精度丢失问题解决方案

JavaScript中的数值计算会存在精度丢失问题,这是因为JavaScript使用IEEE 754标准的浮点数表示法来表示数字,这种表示方法无法精确表示所有数字,特别是涉及到小数的时候。对于小数,前端出现问题的几率还是很多的,先把小数变成整数(乘倍数),再缩小回原来倍数(除倍数)判断两个数的小数位数,取其中较大的小数位数,将两个数都扩大相应倍数,转换成整数。对于整数,前端出现问题的几率可能比较低,只要不超过2^53就不会丢失精度。G|Z|H回复 1 可获取电子书。:因为数据太大,最大数2^53。

2024-03-21 07:58:15 246

原创 JavaScript隐式类型转换原理、优先级、规则及场景

另外,在进行字符串和数字类型的加法操作时,数字类型的值会被转换为字符串类型,然后进行字符串的拼接。需要注意的是,尽管JavaScript引擎能够自动执行隐式类型转换,但在编写代码时,最好还是尽可能地避免隐式类型转换,以减少代码的不确定性和错误。如果一个操作数是布尔值、null 或 undefined,另一个操作数是数字,则进行隐式类型转换为数字,如果另一个操作数是字符串,则执行"字符串拼接"原则。如果两个操作数的类型不同,则 JavaScript 会进行隐式类型转换,以使它们类型相同,并尝试进行比较。

2024-03-20 11:28:35 1136

原创 JavaScript数据类型及差异说明

在 JavaScript 中,基本类型的值是存储在栈内存的变量中,而引用类型的值则是存储在堆内存中的对象,变量实际上是对象的引用。因此,对于引用类型的值,变量存储的是对象的地址,而不是对象本身。存储:基本类型变量的值存储在栈内存中,引用类型变量存储在堆内存中,变量名存储在栈内存中,变量名指向对象在堆内存中的地址。赋值:基本类型变量的赋值是将一个值复制到变量中,而引用类型变量的赋值是将一个对象的引用复制到变量中。变量类型:基本类型的变量直接存储值,而引用类型的变量存储的是对象的引用。

2024-03-19 09:09:23 562

原创 JavaScript变量声明

let定义的变量会形成一个块级作用域,在for,if,while内部定义变量在外部无法进行访问.类似函数内部的变量,这也是形成闭包的一种方式。var定义的变量,只有在function当中定义外部无法访问,其他比如在for,if,while内部定义的都可以在外部进行访问。let不能进行变量的提升,不能进行变量的重复定义,也不能定义其他(var,const)方式已经定义过得变量。const不能进行变量的提升,不能进行变量的重复定义,也不能定义其他(var,let)方式已经定义过得变量。),一旦定义,不能修改。

2024-03-18 07:44:55 256

原创 基于Springboot+Vue的开源小项目 适合新手入门练习

主要包含医生信息、患者信息、挂号信息、药物信息、检查检验信息、病床信息及数据统计等功能。非常适合初级或是刚入门的同学当做学习资料。同时包含设计报告,需要毕业答辩的同学可以参考参考。SpringBoot + Vue + Element UI + mysql 技术栈。基于Springboot+Vue的开源小项目 适合新手入门练习。G|Z|H 回复 医疗 即可免费获取。

2024-03-17 21:35:33 682

原创 uniApp 小程序保存图片到本地实现方案

上述流程只是简单描述图片保存到手机相册的流程,生产环境还有记录下载次数、弹出广告等流程。壁纸、头像类型小程序保存需要支持用户可以保存图片到本地。

2024-03-16 08:34:36 567

原创 微信小程序隐私保护指引弹框实现(uniApp)

从 2023 年 9 月 15 日起必须用户点击同意隐私保护政策并同步给微信之后,开发者才可以调用微信提供的隐私接口。data函数声明变量showPrivacy,methods添加close方法。如有技术问题,可在公众号联系我或评论留意。微信公众平台更新用户隐私保护指引。配置manifest.json。

2024-03-15 09:10:25 543

原创 javascript判断数据类型的方式以及优缺点

最标准的检测数据类型方法,toString是Object原型对象上的一个方法,并不是转为字符串,该方法默认返回其调用者的具体类型,更严格的讲,是toString运行时this指向的对象类型,返回的类型格式为[object,x],x是具体的数据类型,其中包括:String,Number,Boolean,Undefined,Null,Function,Date,Array,RegExp,Error,HTMLDocument,…也就是说,我们可以更改原型链的指向,导致检测数据类型不准确。

2024-03-14 12:26:47 332

原创 JavaScript数据类型

聊一聊JavaScript规定了几种数据类型。公众号回复 1 可获取电子书。

2024-03-13 09:08:24 114

原创 JavaScript规定了几种语言类型

let定义的变量会形成一个块级作用域,在for,if,while内部定义变量在外部无法进行访问.类似函数内部的变量,这也是形成闭包的一种方式。var定义的变量,只有在function当中定义外部无法访问,其他比如在for,if,while内部定义的都可以在外部进行访问。let不能进行变量的提升,不能进行变量的重复定义,也不能定义其他(var,const)方式已经定义过得变量。const不能进行变量的提升,不能进行变量的重复定义,也不能定义其他(var,let)方式已经定义过得变量。),一旦定义,不能修改。

2024-03-12 09:12:18 249

原创 Python爬取股票数据

目标网页-查询指定股票-分析network-找到接口-分析返回数据-读取数据。爬虫练习仅为学习,不做商用,如有侵权,烦请联系删除!依据股票代码爬取股票历史数据。

2024-03-11 13:05:17 381

原创 JavaScript基础(五)

通过使用 JavaScript,我们有能力做到在一个设定的时间间隔之后来执行代码,而不是在函数被调用后立即执行。我们称之为计时事件。注意: setInterval() 和 setTimeout() 是 HTML DOM Window对象的两个方法。所有 JavaScript 全局对象、函数以及变量均自动成为 window 对象的成员。当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息。window.screen对象在编写时可以不使用 window 这个前缀。

2024-03-08 15:48:40 851

基于uniApp技术栈的壁纸、头像类小程序源码

基于uniApp + UniCloud技术栈的壁纸头像类小程序源码 ### 功能 **隐私授权** **壁纸列表** **壁纸预览** **头像列表** **图片下载到本地相册** **流量主** banner、激励、插屏

2024-03-21

Python 爬取股票数据源码实现方案

Python 爬取股票数据源码实现方案

2024-03-19

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除