跳到主要内容

27 篇博文 含有标签「JS」

Javascript

查看所有标签

函数 call, apply, bind 的异同

· 阅读需 1 分钟
Hanasaki
阿巴阿巴阿巴

每一个函数都有这三个方法,平时也不怎么能用到,整的时间长不看真容易迷糊...

function Fn(){}

函数 Fn,可调用 Fn.call(), Fn.apply(), Fn.bind(),下面细说。

const person = {
name: 'Lee',
say: function (greet) {
console.log(`${greet}, I'm ${this.name}`)
}
}
const dog = { name: 'coco' }

person.say('hi') // hi, I'm Lee

person.say.apply(dog, ['woof']) // woof, I'm coco

person.say.call(dog, 'woof') // woof, I'm coco

let person_dog = person.say.bind(dog, 'woof')
person_dog() // woof, I'm coco

相同之处

将调用此函数的 Fn 的 this 指向传入的第一个参数。

不同之处

  1. call 和 apply 立即执行,bind 返回绑定过的函数,需要手动执行。
  2. call 和 bind 传入参数列表,而 apply 则是要求传入一个参数数组
标签:

从 JavaScript 到 TypeScript

· 阅读需 6 分钟
信息

本栏笔记参考TypeScript文档撰写,目前尚无中文翻译,看起来费劲,在这里对其中的要点进行提取,融入自己的理解和示例代码,以中文的笔记形式记录下来。

本文对 TypeScript 进行简要的概述,重点介绍它的类型系统。

类型推断

在声明变量并给他赋值时,会把该值的类型作为该变量的类型。 当鼠标放在 words 上时,IDE会提示它是string类型。

let words = 'hello'

定义类型

默认会推断类型,可以这样创建一个 user 对象,它的 name 属性为字符串类型,id 属性为数字类型。

const user = {
name: 'Lee',
id: 0
}

显式描述类型

interface 事先定义好一个“形”,创建符合这个形的对象 user 时,会把 userUser 定义的属性进行匹配,比较其类型是否相符。以下代码,若缺少定义的属性,会被警告;若类型不匹配,也会被警告。

interface User {
name: string;
id: number;
}
const user: User = {
name: '',
id: 1
}

可以将接口声明和类一起使用,

interface User {
name: string;
id: number;
}
class Teacher {
name: string;
id: number;
constructor(name: string, id: number) {
this.name = name;
this.id = id;
}
}
const user: User = new Teacher("Murphy", 1);

也可以用来注释参数,也可以用来注释返回值的类型

function getUserUser(): User {
return
}
function deleteUser(user: User) {
}

JavaScript 中的原始类型:booleanbigintnullnumberstringsymbolundefined,你可以在接口中使用它们。TypeScript 对这些类型进行了扩展,例如anyunknownnevervoid

定义类型有两种方式,你应该优先选择用 interface,必要时再使用 type

组合类型

可以通过组合简单类型来创建复杂类型。有两种流行的方法可以做到这一点:使用联合类型和泛型。

联合类型

使用联合类型,你可以定义一个可能会是很多种类型其中之一的类型,例如你可以定义一个 MyBool 其值可能是 truefalse

type MyBool = true | false

比较常用的联合类型用法:定义一个可能出现的值的集合,一个字符串集合或数值集合。

type WindowStates = 'open' | 'closed'
type LockStatus = 'locked' | 'unlocked'
type FanSpeed = 1 | 2 | 3 | 4 | 5 | 6

也可以用来定义多种类型的参数,传给函数。例如以下函数,可以接受一个字符串,也可以接受字符串数组

function handle(obj: string | string[]) { }

泛型

type 就像C语言里的 typedef。第三行定义了一个类型:对象数组,对象必须有字符串类型的 name 属性

type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;

定义自己的泛型类型,类比一下 Array<T>

interface Backpack<Type> {
add: (obj: Type) => void;
get: () => Type;
}

结构类型系统

TypeScript的核心原则之一,就是类型检查,实际上是检查“形”里定义的值。在结构类型系统中,如果两个对象有相同的“形”,那么他俩就会被认定是同一类型。

interface Point {
x: number;
y: number;
}
function logPoint(p: Point) {
console.log(p.x, p.y);
}
const point = { x: 12, y: 26 };
const point1 = {x: 1, y: 2, z: new String('3'), n: 4}
logPoint(point); // 输出:12,26
logPoint(point1); // 输出:1,2

从上面的代码可以看到,point 是一个拥有 xy 属性的对象,它从没声明过自己是 Point 类型,但是它通过了类型检查,因为他们有相同的“形”。这个机制用 shape-matching 描述起来更贴切。

shape-matching 匹配只需要是这个对象属性的子集,就匹配通过。即 {'{定义类型属性}'} ∈ {'{对象所有属性}'},在这个例子中就是参数 p 至少包含 x 和 y ,如果有其他属性 z 或者更多也不影响。此规则在类对象上也不例外。

标签:

JavaScript 原型和原型链以及constructor属性

· 阅读需 5 分钟
Hanasaki
阿巴阿巴阿巴

Prototype 原型对象

Prototype 翻译过来叫“原型”,原型是一种在开发生命周期的早期显示应用程序或产品的外观和行为的模型。Javascript 中的 prototype 叫原型对象,是每一个函数都有的属性

npm 运行命令传入参数

· 阅读需 1 分钟
Hanasaki
阿巴阿巴阿巴

写 Github Action 的 配置文件时遇到个问题,想把 secret 密钥在执行 npm run xxx 的时候传进来,并在nodejs程序中用到这个变量。

方法

package.json 部分

  "scripts": {
"action": "node ./src/action.js"
}

action.js

let username, password
username = process.argv[process.argv.indexOf('--username')+1] // 用户名在 --username 后面
password = process.argv[process.argv.indexOf('--password')+1] // 密码在 --password 后面
console.log(username + ' ' + password) // 输出传入的参数

rollup插件执行的先后顺序优先级

· 阅读需 2 分钟
Hanasaki
阿巴阿巴阿巴

官方文档写道:

请注意,大多数情况下@rollup/plugin-commonjs应该在其他插件转化你的模块之前进行,这是为了防止其他插件的更改导致对 CommonJS 的检测被破坏。这个规则的一个例外是 Babel 插件,如果你正在使用它,那么把它放在 commonjs 插件之前。

迷惑的问题来了,如果output中写了好几个输出配置,应该在output中的每一个plugins里把commonjs插件执行放在第一个吗,还是写在外面的plugins里写在第一个?