JavaScript基础编程笔记

47次阅读
没有评论

共计 8548 个字符,预计需要花费 22 分钟才能阅读完成。

编程环境

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 关键字声明的变量会在 global 范围内自动创建。

数据类型

有 6 种:

  • number 数值(BigInt)
  • string 字符串
  • boolean 布尔值
  • null 空值
  • undifined 未定义
  • symbol 符号
  • object 对象

前 5 个属于基本数据类型,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(` 我 ${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 进制的)

<h1>&#9760;</h1>

数组

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__来访问该属性。

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

原型的原型

原型对象也是对象,它也有原型。

function Person() {}
//  向原型中添加 name 属性
Person.prototype.name = " 李小龙 "
var p = new Person()
console.log(p.hasOwnProperty("name")) // false
console.log(p.__proto__.__proto__.hasOwnProperty("hasOwnProperty")) // true

toString()

当打印一个对象时,实际上是输出对象 toString()方法的返回值,可为对象添加一个 toString()自来定义输出。

function Person() {}
Person.prototype.toString = function () {return " 我是李小龙 "}
var p = new Person()
console.log(p.toString())

call()和 apply()

这两个方法都是函数对象的方法,需要通过函数对象来调用。

在调用 call()和 apply()时可将一个对象指定为第一个参数,此时这个对象将会成为函数执行时的 this。

两者区别:

  • call()将实参在对象之后依次传递
  • apply()需要将实参封装到一个数组中统一传递
function func(a, b) {alert(a + b)
}
var obj = {name: " 李小龙 "}
func.call(obj, 1, 2)
func.apply(obj, [3, 4])

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

    1. arguments 是个类数组对象(不是数组),可通过索引来操作数据,也可以获取长度
    2. 它里边有个属性叫 callee,这个属性对应一个函数对象,就是当前正在执行的函数对象
function func() {console.log(arguments[0], arguments.length, arguments.callee)
}
func("obj", 1, 2)

对象

创建对象

// 使用对象字面量创建对象
let obj = {
  name: " 李小龙 ",
  age: 18,
}
console.log(obj) // {name: '李小龙', age: 18}

// 使用 new 关键字创建对象
const obj = new Object()
const obj2 = new 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])
      }
    }
  }
}

正文完
 0
三毛笔记
版权声明:本站原创文章,由 三毛笔记 于2023-08-02发表,共计8548字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)