编辑
2026-04-01
undefined
00

目录

编程环境
Prettier
配置代码片段
Node.js
VSCode 默认终端
安装live-server
VSCode生成html模板
JavaScript组成
输入输出
输入语法
输出语法
代码执行顺序
变量
变量声明
数据类型
strict模式
常量
类型转换
隐式转换
显式转换
转换为string
转换为number
转换为boolean
运算符
赋值
逻辑中断
展开运算符
Unicode编码
数组
新增
删除
去重
排序
合并
遍历
迭代器
伪数组转数组
搜索
函数
命名建议
作用域
原型对象
toString()
call()和apply()
bind()
arguments对象
对象
创建对象
修改对象
遍历对象
冻结对象

编程环境

Prettier

Prettier 是一个 “有主见” 的前端代码格式化工具。

在VSCode中安装好Prettier插件后,可能需要自定义一些配置,可在项目根目录下添加配置文件.prettierrc

{ "singleQuote": true, "arrowParens": "avoid" }

配置代码片段

在VSCode中,「文件」->「首选项」->「配置用户代码片段」->「新建全局代码片段文件...」,输入自定义文件名,回车。在文件中写入: { "Print to console": { "scope": "javascript,typescript", "prefix": "cl", "body": ["console.log($1);"], "description": "Log output to console" } }另外,需要对VSCode做个设置,在设置中搜索snippet,把「控制活动代码段是否阻止快速建议」前面的√取消掉。

Node.js

到Node.js官网:https://nodejs.org/en/ 进行下载安装。

VSCode 默认终端

VSCode 默认是PowerShell终端,修改为CMD的操作步骤如下:

「终端」->「新建终端],在终端界面,点击 + 右边的「∨」->「选择默认配置文件」->「Command Prompt」,重启 VSCode。

安装live-server

npm install live-server -g在静态文件目录下执行:live-server

live-server运行在8080端口下,可以通过127.0.0.1:8080进行访问。

VSCode生成html模板

在设置中搜索「Trigger Expansion On Tab」,前面打上√。然后就能用! + tab自动生成html模板了。

JavaScript组成

ECMAScript是一种语言标准,规定了JavaScript基础语法核心知识,而JavaScript是网景公司对ECMAScript标准的一种实现。

Web APIs:

  • DOM 操作文档,比如对页面元素进行移动、大小、添加制除等操作。
  • BOM 操作浏览器,比如页面弹窗,检测窗口宽度、存储数据到浏览器等等。

JavaScript权威网站:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript

输入输出

输入语法

prompt("请输入姓名:")

输出语法

// 向body输出内容 document.write("输出的内容") // 页面弹出警告对话框 alert("输出的内容") // 控制台输出语法,程序员调试使用 console.log("控制台打印")

代码执行顺序

  • 按HTML文档流顺序执行JavaScript代码
  • alert()和prompt()会跳过页面染先被执行

变量

变量声明

let age // 变量声明 console.log(age) // 此时age的值为undefined age = 18 // 变量赋值 console.log(age) // 此时age的值为18 console.log(typeof age) // number 作为运算符(推荐) console.log(typeof age) // number 函数形式

let name, city // 一次性声明多个变量

let sex = 1 // 变量初始化

使用let声明的变量具有块作用域,在代码块{}中声明的变量无法在代码块的外部访问。

在局部作用域中,未使用let或const关键字声明的变量,会自动成为window对象的属性,也就是全局变量。

数据类型

7种原始类型(Primitive Types):

  • Undifined未定义
  • Null空值。typeof null返回 'object'是历史遗留问题,判断null使用===
  • Boolean布尔值
  • Number数值
  • BigInt
  • String字符串
  • Symbol符号

原始类型属于基本数据类型,其值直接在栈内存中存储。

1种复杂类型(Complex Type):

  • Object对象

复杂类型属于引用数据类型,其值是保存到堆内存中的,每创建一个新对象,就会在堆内存中开辟出一个新空间,而变量保存的是对象内存地址。

JavaScript不区分整数和浮点数,统一用number表示。

console.log(10.0 === 10) // true console.log(Math.abs(1 / 3 - (1 - 2 / 3)) < 0.0001) // true 浮点数比较 // NaN(Not a Number)这个特殊Number与所有其他值都不相等,包括它自己。 // NaN是粘性的,任何对NaN的操作都会返回NaN console.log(NaN === NaN) // false console.log(NaN + 1) // NaN console.log(isNaN(NaN)) // true 唯一能判断NaN的方法 console.log(9007199254740993) // 9007199254740992 // 比 2^53 大的整数,可使用内置 BigInt 类型,表示方法是在整数后加一个 n var a = 9007199254740993n var b = BigInt(9007199254740993) // 使用 BigInt() 把 Number 转成 BigInt var c = BigInt('0x20000000000001')// 把字符串转成 BigInt console.log(a === b, a === c) // false true

null和undefined:

  • null表示一个“空”值(空对象指针),常用于主动将一个变量或对象引用设置为空,表示“此处曾有过值,但现在没有了”
  • undefined表示值“未定义”(值还不存在)
  • 大多数情况下,都应该用null
  • undefined仅在判断函数参数是否传递的情况下有用

console.log(null + 1) // 1

let money console.log(money + 100) // NaN对undefined进行运算操作,结果是NaN console.log(money + '100') // undefined100用undefined连接字符串,将得到一个含undefined的字符串

模板字符串:let age = 18 // 外面用反引号,里面用变量名console.log({变量名} console.log(`我{age}岁了`) // 我18岁了

字符串是不可变的,对字符串某个索引赋值,不会有任何错误,但也没有任何效果:

let s = 'abc' s[1] = 'd' console.log(s) // abc

JavaScript有两种比较运算符:

  • ==会自动转换数据类型再比较
  • ===不会自动转换数据类型,如果数据类型不一致,返回false,如果一致,再比较

不要使用==比较,始终坚持使用===比较。

strict模式

在strict模式下运行的JavaScript代码,强制申明变量,未申明变量就使用,将导致运行错误。 'use strict' age = 18 // 报错 age is not define

常量

用const关键字声明的变量是只读的。一旦一个变量被赋值为const,它就不能被重新赋值。 const G = 9.8 console.log(G)但是,使用const分配给变量的对象(包括数组和函数)仍然是可变的。使用const声明只能防止变量标识符的重新分配。为了确保数据不被改变,JavaScript提供了一个函数Object.freeze。 const MATH_CONSTANTS = { PI: 3.14, } Object.freeze(MATH_CONSTANTS)

类型转换

隐式转换

规则:

  • +号两边只要有一个是字符串,都会把另外一个转成字符串
  • 除了+以外的算术运算符,比如 - * / 等都会把数据转成数字类型

小技巧:

  • +号作为正号解析可以转换成数字型
  • 任何数据和字符串相加结果都是字符串 console.log(+"111") //转换为数字型

显式转换

转换为string

null和undifined没有toString()方法,使用String()方法会将null直接转换为"null",将undifined直接转换为"undifined"。

转换为number

Number()

  1. 如果是纯数字的字符串,则直接将其转换为数字
  2. 如果字符串中有非数字的内容,则转换为NaN
  3. 如果字符串是一个空串或全是空格,则转换为0
  4. true转成1,false转成0
  5. null转成0
  6. undifined转成NaN

**parseInt()**将一个字符串中的有效整数内容取出来,然后转换为number。

parseFloat() 作用和parseInt()类似,不同的是它可以获得有效的小数。

转换为boolean

  • 除了0和NaN,其余都是true
  • 除了空串,其余都是true
  • null和undefined都会转换为false
  • 对象转换为true

运算符

赋值

??=为空赋值,只有当变量的值为null或undefined时才会对变量进行赋值: let a = 100 a ??= 200 console.log(a) //100

a = null a ??= 200 console.log(a) //200

?.是链判断运算符,允许开发人员读取深度嵌套在对象链中的属性值,而不必验证每个引用。当引用为空时,表达式停止计算并返回undefined。let s1 = { name: '张三', address: { city: '北京', }, } let s2 = { name: '李四', address: null, } function test(stu) { console.log(stu.address?.city) } test(s1) //北京 test(s2) //undefined

逻辑中断

短路:只存在于&&和||中,当满足一定条件会让右边代码不执行。

  • &&:左边为false就短路
  • ||:左边为true就短路

原因:通过左边能得到整个式子的结果,因此没必要再判断右边。

运算结果:无论&&还是||,运算结果都是最后被执行的表达式值,一般用在变量赋值。

console.log(11 && 22) //22 console.log(11 || 22) //11

展开运算符

展开运算符(...)能将一个数组进行展开,典型应用场景:求数组最大值、合并数组等。 const arr = [1, 3, 4] console.log(Math.max(...arr)) //4

const arr1 = [1, 3, 4] const arr2 = [2, 8, 9] const arr = [...arr1, ...arr2] console.log(arr) //[1, 3, 4, 2, 8, 9]

let obj = { name: '张三', age: 18 } let obj2 = { ...obj } //复制对象 console.log(obj2)

Unicode编码

在字符串中使用转义字符输入Unicode编码,u四位编码 console.log("u2620")在网页中使用Unicode编码,&#编码;(编码是10进制的)

数组

let arr = [1, 2, 3, 4] // 声明数组 console.log(arr[0]) // 1 console.log(arr.length) // 数组长度 arr.length = 6 // 改变数组长度会导致Array大小变化 console.log(arr) // [ 1, 2, 3, 4, <2 empty items> ]

console.log(arr.slice(1, 3)) // [ 2, 3 ] 切片操作 console.log(arr.slice(1)) // [ 2, 3, 4, <2 empty items> ]

新增

let arr = [1, 2, 3] arr.push("4") console.log(arr) //[1, 2, 3, "4"] arr.unshift(5) console.log(arr) //[5, 1, 2, 3, "4"]

删除

let arr = [1, 2, 3, 4] arr.pop() console.log(arr) //[1, 2, 3] arr.shift() console.log(arr) //[2, 3]

let arr2 = [1, 2, 3, 4, 5, 6] arr2.splice(1, 2) // 只删除,不添加 console.log(arr2) // [1, 4, 5, 6] arr2.splice(1, 2, '7', '8', '9') // 删除后添加 console.log(arr2) // [1, '7', '8', '9', 6] arr2.splice(1, 0, 10) // 只添加,不删除 console.log(arr2) // [ 1, 10, '7', '8', '9', 6 ]

去重

const arr = [1, 2, 1, 66, 2, 1, 9, 5] for (let i = 0; i < arr.length; i++) { const index = arr.indexOf(arr[i], i + 1) if (index !== -1) { arr.splice(index, 1) i-- } } console.log(arr)

const newArr = [] for (let i of arr) { if (newArr.indexOf(i) === -1) { newArr.push(i) } } console.log(newArr)

排序

let arr = [2, 4, 3, 5, 1] arr.sort() //默认升序 console.log(arr) //[1, 2, 3, 4, 5] arr.sort((a, b) => b - a) //降序 console.log(arr) //[5, 4, 3, 2, 1]

let arr2 = [ { name: "张三", age: 18, }, { name: "李四", age: 20, }, { name: "王五", age: 19, }, ] arr2.sort((a, b) => b.age - a.age) //按age降序 console.log(arr2)

合并

let arr = [1, 2] let arr2 = [3, 4] let arr3 = arr.concat(arr2, 5, 6) console.log(arr3) // [1, 2, 3, 4, 5, 6]

console.log(arr3.join('-')) // 1-2-3-4-5-6

遍历

let arr = [1, 2, 7, 8] let r1 = arr.every((item) => item > 5) console.log(r1) //false

let r2 = arr.some((item) => item > 5) console.log(r2) //true

let r3 = arr.filter((item) => item > 5) console.log(r3) //[7, 8]

let r4 = arr.map((item) => "age=" + item) console.log(r4) //['age=1', 'age=2', 'age=7', 'age=8']

let r5 = arr.reduce((item1, item2) => item1 + item2) //累加 console.log(r5) //18

arr.forEach((item, index) => { console.log(index, item) })

注意:在forEach里面return不会终止迭代。

迭代器

let arr = [1, 2, 7, 8] for (let i of arr) { console.log(i) //1 2 7 8 }

let arr = [1, 2, 7, 8] for (let i of arr.entries()) { console.log(i) //entries()是键值对,keys()是键,values()是值 }

伪数组转数组

function f() { a = Array.from(arguments) console.log(a.map((item) => "age=" + item)) } f(18, 19, 20) //['age=18', 'age=19', 'age=20']

搜索

let arr = [1, 13, 2, 44] console.log(arr.indexOf(13)) //1 找不到返回-1 console.log(arr.includes(13)) //true

console.log(arr.find((item) => item > 10)) //13 console.log(arr.findLast((item) => item > 10)) //44

console.log(arr.findIndex((item) => item > 10)) //1 console.log(arr.findLastIndex((item) => item > 10)) //3

函数

命名建议

常用动词约定含义can判断是否可执行某个动作has判断是否含有某个值is判断是否为某个值get获取某个值set设置某个值load加载某些数据

作用域

变量有一个坑,特殊情况:如果函数内部,变量没有声明,直接赋值,会当全局变量看,但是强烈不推荐。 function fn() { num = 10 } fn() console.log(num) //10

原型对象

创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是所谓的原型对象

当函数以构造函数调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,可以通过__proto__来访问该属性。

当访问对象的一个属性或方法时,会先在对象自身中寻找,有则直接使用,没有则会去原型对象中寻找(找到直接使用)。

通过__proto__能访问对象的原型,还可以通过类的prototype属性,来访问实例的原型。修改原型时,最好通过类去修改,好处:

  • 一修改就是修改所有实例的原型
  • 无需创建实例即可完成对类的修改

原则上,原型尽量不要手动改。要改也不要通过实例对象去改,而是通过类.prototype去修改,且最好不要直接给prototype去赋值。

原型对象也是对象,它也有原型,即原型的原型。0bject是所有对象的原型,所以任何对象和0bject进行instanceof运算都会返回true。

class Person {} // 向原型中添加name属性 Person.prototype.name = '李小龙' const p = new Person() console.log(p.hasOwnProperty('name')) // false console.log(p.proto.hasOwnProperty('name')) // true

使用in运算符检查属性时,无论属性在对象自身还是在原型中,都会返回true。而对象.hasOwnProperty(属性名)用来检查一个对象自身是否含有某个属性。使用Object.hasOwn(对象,属性名)也可以用来检查一个对象自身是否含有某个属性,推荐使用这个方法。

早期JS中,直接通过函数来定义类。一个函数如果直接调用xxx(),那么这个函数就是一个普通函数。一个函数如果通过new调用new xxx(),那么这个函数就是一个构造函数。

toString()

当打印一个对象时,实际上是输出对象toString()方法的返回值,可为对象添加一个toString()自来定义输出。 function Person() {} Person.prototype.toString = function () { return "我是李小龙" } var p = new Person() console.log(p.toString())

call()和apply()

调用函数除了通过函数()这种形式外,还可以通过其他的方式来调用函数。比如,可以通过调用函数对象的call()和apply()两个方法来调用函数函数。

  • call和apply除了可以调用函数,还可以用来指定函数中的this
  • call和apply的第一个参数,将会成为函数执行时的this
  • 通过call方法调用函数,函数的实参直接在第一个参数对象之后依次传递
  • 通过apply方法调用函数,函数的实参需要将实参封装到一个数组中统一传递

function fn(a, b) { alert(${a} + ${b} = ${a + b}) } const obj = { name: '李小龙' } fn.call(obj, 1, 2) fn.apply(obj, [3, 4])

bind()

bind()是函数对象的方法,用来创建一个新函数。

  • bind可以为新函数绑定this
  • 也可以为新函数绑定参数

function fn(a, b, c) { console.log(a, b, c, this) } const obj = { age: 18 } const newFn = fn.bind(obj, 1, 2, 3) newFn()

arguments对象

在调用函数时,浏览器会传递进两个隐含的参数:

  1. 函数的上下文对象this

  2. 封装实参的对象arguments

  3. arguments是个类数组对象(不是数组),可通过索引来操作数据,也可以获取长度

  4. 它里边有个属性叫callee,这个属性对应一个函数对象,就是当前正在执行的函数对象

function func() { console.log(arguments[0], arguments.length, arguments.callee) } func("obj", 1, 2)

对象

在浏览器中,浏览器提供了一个window对象,window对象的属性可以通过window对象直接访问,访问函数就可以认为是window对象的方法。window对象代表浏览器窗口,通过该对象可以对浏览器窗口进行各种操作。除此之外,window对象还负责存储JS中的内置对象和浏览器的宿主对象。

注意:使用let声明的变量不会存储在window对象中,而是存在一个无法访问的秘密小地方。

let a = 'a1' window.a = 'a2' console.log(a) // a1

创建对象

在使用变量存储对象时,很容易因为改变变量指向的对象,提高代码的复杂度。所以通常情况下,声明存储对象的变量时会使用const。const只是禁止变量被重新赋值,对对象的修改没有任何影响。 // 使用对象字面量创建对象 const obj = { name: "李小龙", age: 18, } console.log(obj) // {name: '李小龙', age: 18}

// 使用 new 关键字创建对象,new 可以省略 const obj = new Object() const obj2 = Object({ name: "李小龙" })

// 使用构造函数创建对象 function Pig(name, age, sex) { this.name = name this.age = age this.sex = sex } const Peppa = new Pig("佩奇", 3, "女") const George = new Pig("乔治", 4, "男")

使用new关键字调用的函数,是构造函数(专门用来创建对象的函数)。

修改对象

在使用变量存储对象时,很容易因为改变变量指向的对象,提高代码的复杂度。所以通常情况下,声明存储对象的变量时会使用const。

遍历对象

let mySymbol = Symbol() let obj = { name: '李小龙', age: 18, [mySymbol]: '我是特殊属性', }

for (let k in obj) { console.log(k, '=', obj[k]) }

符号添加的属性不能枚举。

冻结对象

const obj = { name: "佩奇", age: 10, hobby: { one: "唱歌", }, } Object.freeze(obj) //浅冻结,使第一层数据不可修改

// 深冻结数据 function deepFreeze(obj) { Object.freeze(obj) for (let i in obj) { if (obj.hasOwnProperty(i)) { if (typeof obj[i] === "object") { deepFreeze(obj[i]) } } } }

本文作者:a

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!