想起上次面试,被问了个古老的问题:watch 和 computed 的区别。多少有点感慨,现在已经很少见这种耳熟能详的问题了,网络上八股文不少。今天,我更想分享一下从源码的层面来区别这八竿子打不着的两者。上一篇看了watch的源码,本篇针对computed做分析。 一、类型声明computed的源码在reactivity/src/computed.ts里,先来看看相关的类型定义: ComputedRef:调用computed得到的值的类型,继承自WritableComputedRef; WritableComputedRef:继承自Ref,拓展了一个effect属性; ComputedGetter:传递给ComputedRef的构造器函数,用于创建effect; ComputedSetter:传递给ComputedRef的构造器函数,用于在实例的值被更改时,即在set中调用; WritableComputedOptions:可写的Computed选项,包含get和set,是computed函数接收的参数类型之一。 1234567891011121314151617181920212 ...
想起上次面试,问了个古老的问题:watch 和 computed 的区别。多少有点感慨,现在已经很少见这种耳熟能详的问题了,网络上八股文不少。今天,我更想分享一下从源码的层面来区别这八竿子打不着的两者。本篇针对watch做分析,下一篇分析computed。 一、watch参数类型我们知道,vue3里的watch接收三个参数:侦听的数据源source、回调cb、以及可选的optiions。 1. 选项options我们可以在options里根据需要设置immediate来控制是否立即执行一次回调;设置deep来控制是否进行深度侦听;设置flush来控制回调的触发时机,默认为{ flush: 'pre' },即vue组件更新前;若设置为{ flush: 'post' }则回调将在vue组件更新之后触发;此外还可以设置为{ flush: 'sync' },表示同步触发;以及设置收集依赖时的onTrack和触发更新时的onTrigger两个listener,主要用于debugger。wa ...
一、XMLHttpRequest 对象所有现代浏览器都支持通过XMLHttpRequest构造函数来原生支持XHR对象:const xhr = new XMLHttpRequest()。 1. 使用XHR使用XHR第一步便是调用open()方法,其接收三个参数:请求的类型(如get),url,以及一个布尔值表示请求是否为异步。例如,xhr.open('get', 'www.baidu.com', false) 表示将要向www.baidu.com发送一个同步的get请求。有两点需要注意: 这里得第二个参数url一般是相对于当前页面的,不过也可以使用绝对URL; 调用open()方法只是进行初始化,并不会立即发送请求,而是为发送请求做准备,真正开始发送请求还需要调用send()方法。 send()方法接收一个参数,表示作为请求体发送的数据。xhr.send({username: 'cc', pwd: 'lovecake'})。如果不需要请求体,则必须传入null:xhr.send(null)。调用se ...
ES6新增了class来替代之前的构造函数,并且通过extends关键字可以轻易实现继承。不过ES的概念中,暂时还没有class这一类型,不管从哪方面来看,class都是对之前的继承方案的封装,其本质上是函数(Function的实例) 。了解一下ES6之前的各种继承方案,有助于加深对class继承的理解。 一、创建对象1. 工厂模式当需要创建多个对象实例,且他们的属性高度重复时,无论是通过对象字面量来创建,还是使用new Object来创建,都非常麻烦。采用工厂模式,可以很方便地批量创建多个具有相同属性的对象实例,为此,需要定义一个工厂函数: 123456789101112131415161718192021// 定义一个工厂函数,用于创建对象function createPerson(name, age, gender, ...rest) { // 创建一个空对象person const person = {}; // 将参数上的属性添加到person上(增强对象) person.name = name; person.age = age; ...
自ES6中symbol问世以来,个人在项目中并没有太多机会使用到,小公司业务项目没有给symbol太多的登场机会。因此之前也只稍微知晓了概念,没有详细了解。如今重温js,自然要重新认识一下这独一无二的symbol。如你所知,symbol是原始值(基本数据类型),其每个实例是独一无二且不可变的,一般作为对象属性使用,确保对象属性独一无二,避免属性冲突。 [toc] 1. 基本用法符号只能通过函数来创建实例。最基本的就是Symbol()函数:可以使用Symbol()函数来创建一个符号实例。有以下几点需要注意: Symbol()函数不与new操作符搭配,即new Symbol()是不合法的。这是为了防止创建Symbol包装对象; Symbol()函数可以传入字符串作为键(也可以不传),此时传入的字符串键只起到描述的作用,并不影响symbol实例的值。因此,传入相同的字符串键的symbol实例,其值也不相等而且相互之间也没啥关联。 12345let symbol1 = Symbol("a");let symbol2 = Symbol("a");// ...
一个月前,更新了TS系列。本来要继续其它内容,奈何公司项目开始了,忙到现在,总算能缓一缓。也准备趁机开始源码系列。但是在此之前,我想先温习一下JS系列,查漏补缺,内容主要基于《JS高级程序设计》 1. script标签的 8 个属性 async: 立即下载,但不阻止其它页面动作,如下载资源或等待其它脚本加载;仅对外部脚本文件有效(即src指定路径的文件),保证脚本在页面的load事件之前执行,但不保证脚本执行的顺序。 charset: 使用src属性指定的字符集,这个属性基本不会用到。 crossorigin: 配置相关请求的CORS设置。默认不使用CORS。 defer: 使脚本延迟到页面内容解析之后再执行,html5规范要求脚本按照出现的顺序依次执行,只对外部文件有效,但IE7及更早版本对行内脚本也有效。 intergrity: 允许验证子资源的完整性,一般情况下不会用到。 language: 已废弃。 type: 设置为type="module"才能允许其中的代码被当成ES6模块,从而允许使用import,export等关键字。 src: 表示包含指定的要执行 ...
一、函数式编程的出现 发展史:命令(脚本)式 -> 面向对象 -> 函数式编程 1. 从实际问题开始123456789101112131415161718192021222324252627// 1.数组在 `url` 中展示形式location.search => '?name[]=progressive$%coding&name[]=objective$%coding&name[]=functional$%coding'// 2.参数提取拼接成数组['progressive$%coding', 'objective$%coding', 'functional$%coding']// 3. 手写方法,转换成数组对象// [{name: 'Progressive Coding'}, {name: 'Objective Coding'}, {name: 'Functional ...
模块有自己的作用域,除非进行某种形式的导出,否则,其中的变量,函数,类等都是对外不可见的。相应的,如果要在模块外使用其导出的成员,则需要进行相应的导入。模块的相互导入需要使用 模块加载器 ,模块加载器在执行模块之前,会先定位并执行该模块的依赖项。JS中主要使用Node.js的CommonJs模块加载器和Web应用程序中的AMD模块的RequireJs加载器。TS 延用了ES2015模块化方案,任何包含了顶层的import或export语句的文件,便是一个模块;相反,没有在顶层包含这些语句的则是脚本,其内容在全局作用域中可见。 [toc] 一、导出1. 导出一个声明任何声明 (变量、函数、类、类型等) 都可以使用export关键字来导出。 12345678910111213141516171819export let a = 1;export const b = { a: 2 };export function cc() {}export class CC {}export type A = string | number;ex ...
在接触 TS 的过程中,时常能看到使用declare关键字来进行声明,而它基本都是出现在.d.ts文件中。你是否好奇过,使用declare关键字到底有什么作用?它与不使用declare关键字的声明又有何不同?本文与你一同探索declare的奥秘,讲述如何写好一个声明文件 (.d.ts文件),需要小伙伴们拥有一定的typescript基础。如果阅读本文过程中遇到不了解的知识点,可查阅我之前的基础篇的文章。 [toc] 一、Declaration Reference 声明指南我们先来了解到如何根据API文档和用法示例来编写相关的声明。这部分内容十分简单,基本看一遍过去就ok了。 1. 对象和属性我们通常使用命名空间来声明对象。 文档: 全局变量myLib,它有一个greet方法来创建问候语,一个numberOfGreetings属性来记录创建的问候语的数量。 示例: 123let greeting = myLib.greet("hello, cc!");console.log(greeting);let count = myLib.numberOfGreetin ...
上一篇介绍namespace多文件拆分的内容时,用到了一个三斜杠指令/// <reference path="xxx" />。这组指令有多个,其作用分别有所不同。有些同学还不是很了解这个语法,因而本文专门来介绍相关指令。 〇、注意事项三斜杠指令是包含一个XML单标签的单行三斜杠注释,注释的内容可被编译器识别,用来指示编译器在编译的过程中包含其它文件,或者用作规定文件输出顺序的方法。使用三斜杠指令时需要注意:只有出现在文件的开头才有效,否则将被当作没有特殊意义的普通注释。这意味着,在三斜杠指令之前,只能有单行或多行注释的存在,当然也可以有其它的三斜杠指令,而不能有其它的语句或者声明。 一、/// <reference path="..." />这是最常用的指令了,用来声明文件之间的依赖关系。 1. 预处理输入文件编译器将所有的三斜杠指令通过预处理传递输入文件的方式来解析,在此过程中,其它的文件会被添加到编译中。这个过程会从一系列根文件,即通过命令行或者tsconfig.json中指定的文件,按照指定的顺序开始开始。在文件被添 ...