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官网:https://nodejs.org/en/ 进行下载安装。
VSCode 默认是PowerShell终端,修改为CMD的操作步骤如下:
「终端」->「新建终端],在终端界面,点击 + 右边的「∨」->「选择默认配置文件」->「Command Prompt」,重启 VSCode。
npm install live-server -g在静态文件目录下执行:live-server
live-server运行在8080端口下,可以通过127.0.0.1:8080进行访问。
在设置中搜索「Trigger Expansion On Tab」,前面打上√。然后就能用! + tab自动生成html模板了。
ECMAScript是一种语言标准,规定了JavaScript基础语法核心知识,而JavaScript是网景公司对ECMAScript标准的一种实现。
Web APIs:
JavaScript权威网站:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript
prompt("请输入姓名:")
// 向body输出内容 document.write("输出的内容") // 页面弹出警告对话框 alert("输出的内容") // 控制台输出语法,程序员调试使用 console.log("控制台打印")
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):
typeof null返回 'object'是历史遗留问题,判断null使用===原始类型属于基本数据类型,其值直接在栈内存中存储。
1种复杂类型(Complex Type):
复杂类型属于引用数据类型,其值是保存到堆内存中的,每创建一个新对象,就会在堆内存中开辟出一个新空间,而变量保存的是对象内存地址。
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:
console.log(null + 1) // 1
let money console.log(money + 100) // NaN对undefined进行运算操作,结果是NaN console.log(money + '100') // undefined100用undefined连接字符串,将得到一个含undefined的字符串
模板字符串:let age = 18 // 外面用反引号,里面用{age}岁了`) // 我18岁了
字符串是不可变的,对字符串某个索引赋值,不会有任何错误,但也没有任何效果:
let s = 'abc' s[1] = 'd' console.log(s) // abc
JavaScript有两种比较运算符:
不要使用==比较,始终坚持使用===比较。
在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)
规则:
小技巧:
null和undifined没有toString()方法,使用String()方法会将null直接转换为"null",将undifined直接转换为"undifined"。
Number()
**parseInt()**将一个字符串中的有效整数内容取出来,然后转换为number。
parseFloat() 作用和parseInt()类似,不同的是它可以获得有效的小数。
??=为空赋值,只有当变量的值为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
短路:只存在于&&和||中,当满足一定条件会让右边代码不执行。
原因:通过左边能得到整个式子的结果,因此没必要再判断右边。
运算结果:无论&&还是||,运算结果都是最后被执行的表达式值,一般用在变量赋值。
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编码,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()自来定义输出。 function Person() {} Person.prototype.toString = function () { return "我是李小龙" } var p = new Person() console.log(p.toString())
调用函数除了通过函数()这种形式外,还可以通过其他的方式来调用函数。比如,可以通过调用函数对象的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()是函数对象的方法,用来创建一个新函数。
function fn(a, b, c) { console.log(a, b, c, this) } const obj = { age: 18 } const newFn = fn.bind(obj, 1, 2, 3) newFn()
在调用函数时,浏览器会传递进两个隐含的参数:
函数的上下文对象this
封装实参的对象arguments
arguments是个类数组对象(不是数组),可通过索引来操作数据,也可以获取长度
它里边有个属性叫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 许可协议。转载请注明出处!