目录
js假值
一共有6个,分别是
null,undefined,false,0,NaN,''
- NaN不等于任何值,包含本身
NaN===NaN //false
- undefined + 任何值 = NaN,除了加字符串。
- 转换undefined为数字型,也是NaN
- 字符串转数字,除了数字字符串会转为数字,其他的转换也是NaN
- parseInt(),转除了数字字符串和数字型以外的,也是NaN
- parseFloat(),转除了数字字符串和数字型以外的,也是NaN
//
console.log(1 + undefine) // NaN
console.log('123' + undefined) // 123undefined
//
console.log(Number(undefined)) // NaN
console.log(undefined - 0) // NaN
//
let str = '99' // 数字字符串
console.log(Number(str)) // 99
let s = 'a'
console.log(Number(s)) // NaN
// parseInt() 只能转换数字字符串和数字型的,会向下取整
console.log(parseInt('123')) // 123
console.log(parseInt(99)) // 99
console.log(parseInt(99.99)) // 99
console.log(parseInt('a')) // NaN
console.log(parseInt(true)) // NaN
console.log(parseInt(null)) // NaN
console.log(parseInt(undefined)) // NaN
// parseFloat() 也是只能转换数字字符串和数字型的,但是会保留小数
console.log(parseFloat('123.09')) // 123.09
console.log(parseFloat(99)) // 99
console.log(parseFloat(99.99)) // 99.99
console.log(parseFloat('a')) // NaN
console.log(parseFloat(true)) // NaN
console.log(parseFloat(null)) // NaN
console.log(parseFloat(undefined)) // NaN
js表达式&js语句
表达式就是会产生一个结果(值)的代码,可以写在右侧
let count = 10 + 20 // 右面就是一个表达式,会产生一个具体的值
语句就是一段可执行的代码(for,if,log,dir,alert...)
for(let i = 0;i < 9;i++) { console.log(i) } // 这个就是个js语句,不会产生值,就是执行
== 与 ===
双等只需要值相等,数据类型可以不同
null == undefined // true
三等既需要值相等,数据类型也要相同
null === undefined // false
一元运算符 与(& &&)或(| ||)非(!)
- & 和 &&(短路与) 全真才为真
// 值对比
console.log(0 & 1) // 0
console.log(0 && true) // 0
// 值与表达式对比
console.log(2 + 5 & 0) // 0
console.log(2 + 5 && 0) // 0
console.log(2 + 5 & false) // 0
// 值与语句对比
0 & console.log('左为假,单&,执行了') // 输出了,因为单&,前后都会对比,所以不管前面真假都会输出
1 & console.log('左为真,短路&,执行了') // 输出了,同上
0 && console.log('左为假,单&,执行了') // 未执行,因为短路&,前面的为假,就不会执行后面的了
1 && console.log('左为真,短路&,执行了') // 执行了,推荐用这个,可以代替简单的if判断
- | 和 ‖(短路或) 全假才为假
// 值对比
console.log(0 | 1) // 1
console.log(0 || true) // true
// 值与表达式对比
console.log(2 + 5 | 0) // 7
console.log(2 + 5 || 0) // 7
console.log(2 + 5 | false) // 7
// 值与语句对比
0 | console.log('左为假,单|,执行了') // 输出了,因为单|,前后都会对比,所以不管前面真假都会输出
1 | console.log('左为真,单|,执行了') // 输出了,同上
0 || console.log('左为假,短路|,执行了') // 执行了,推荐用这个,可以代替简单的if判断
1 || console.log('左为真,短路|,执行了') // 未执行,因为短路|,前面的为真,就不会执行后面的了
- !取反操作
console.log(!0) // true
console.log(!1) // false
console.log(!true) // false
console.log(!false) // true
console.log(!(99 - 9)) // true
数据类型
基本数据类型
string,number,boolean,undefined,null,symbol
复杂(引用)数据类型
Object(Array,Function),Map,Set
- 通过 typeof() 判断数据类型
类型转换
转字符串:toString(),'' + 其他(隐式转换),String()
// 数值
let num = 99
console.log(String(num)) // '99'
console.log(typeof (String(num))) // string
// 布尔
let flag = true
console.log(flag + '123') // 'true123'
// undefined
let un = undefined
console.log(String(un)) // 'undefined'
console.log(typeof (String(un))) // string
// 对象,toString是从Object基类继承下来的
const obj = { name: 'zs' }
console.log(obj.toString()) // '[object Object]'
console.log(typeof (obj.toString())) // string
转数字型:Number(),+号(隐式转换),-*/(隐式转换),parseInt(),parseFloat()
// 假值转换成数字型,都会为0
// 布尔
let flag = true
console.log(flag - 0) // 1
// null
let n = null
console.log(+n) // 0
// string,只能转换数字字符串,其他的也是NaN
let str = '99' // 数字字符串
console.log(Number(str)) // 99
let s = 'a'
console.log(Number(s)) // NaN
// undefined,注意这个,这个不管强转还是隐式转换,都是NaN
let un = undefined
console.log(un - 0) // NaN
console.log(Number(un)) // 0
// parseInt() 只能转换数字字符串和数字型的,会向下取整
console.log(parseInt('123')) // 123
console.log(parseInt(99)) // 99
console.log(parseInt(99.99)) // 99
console.log(parseInt('a')) // NaN
console.log(parseInt(true)) // NaN
console.log(parseInt(null)) // NaN
console.log(parseInt(undefined)) // NaN
// parseFloat() 也是只能转换数字字符串和数字型的,但是会保留小数
console.log(parseFloat('123.09')) // 123.09
console.log(parseFloat(99)) // 99
console.log(parseFloat(99.99)) // 99.99
console.log(parseFloat('a')) // NaN
console.log(parseFloat(true)) // NaN
console.log(parseFloat(null)) // NaN
console.log(parseFloat(undefined)) // NaN
转布尔型:Boolean()
// 假值转换成布尔,都会为false
console.log(Boolean(0)) // false
console.log(Boolean(1)) // true
console.log(Boolean(undefined)) // false
console.log(Boolean(null)) // false
console.log(Boolean('a')) // true
console.log(Boolean('')) // false
递增/减
递增递减单独使用
let num = 10
// 前++/--,会先进行自增/减
console.log(++num) // 11
console.log(--num) // 10
// 后++/--,会先进行紧挨的操作,操作完成后再自增/减
console.log(num++) // 10,因为它会先进行输出,输出后(10),num自增(10 + 1),这时num是11
console.log(num--) // 11,因为它会先进行输出,输出后(11),num自减(11 - 1),这时num是10
递增递减参与运算时
- 前增/减,先自增/减,再参与运算
- 后增/减,先参与当前次运算,然后再自增/减
let num = 10
// 前++/--,会先进行自增/减
console.log(10 + ++num) // 21,num会先自增(10 + 1),此时的num为11,然后参与运算(10 + (10 + 1))
console.log(10 + --num) // 20,num会先自减(11 - 1),此时的num为10,然后参与运算(10 + (11 - 1))
// 后++/--,会先进行紧挨的操作,操作完成后再自增/减
console.log(10 + num++) // 20,因为它会先进行运算(10 + 10),输出后(20),num自增(10 + 1),这时num是11
console.log(num) // 11
console.log(10 + num--) // 21,因为它会先进行运算(10 + 11),输出后(21),num自减(11 - 1),这时num是10
console.log(num) // 10
练习:
let num = 10
let res = num++ + 10 - num-- + ++num
// 1. num + 10 = 20 num = 11
// 2. 20 - 11 = 9 num = 10
// 3. 9 + 11 = 20 num = 11
console.log(res) // 20
循环语句
switch...case
- 一般用于等值运算,不适合区间判断
let i = 2
switch (i) {
case 0:
console.log(0);
break;
case 1:
console.log(1);
break;
case 2:
console.log(2);
break;
default:
console.log('...');
break;
}
for
- 适合不确定次数的,并且不会跳过假值,里面的变量是局部变量
for (var i = 0; i < 10; i++) {
console.log(i);
}
// 不会跳过假值
const arr = [, , , , ,]
for (let i = 0; i < arr.length; i++) {
arr[i] = 'a' + i
}
console.log(arr) // ['a0', 'a1', 'a2', 'a3', 'a4']
while
- 适合确定次数的
let i = 0
while (i < 3) {
console.log(i)
i++
}
无限循环
while(true) {} 或 for(;;;){}
判断是否为数组
- Array.isArray(),会返回一个布尔值
- insranceOf 运算符,会判断是否在其原型链上
let arr = [1, 2, 3]
// Array.isArray(arr)
console.log(Array.isArray(arr)) // true
// instanceof 运算符
console.log(arr instanceof Array) // true
函数相关
函数的参数可以传入默认值
function 函数名(参数名 = 默认值){ 函数体 }
形参当成局部变量
unction fn(args) {
return args
}
console.log(fn(99)) // 99
console.log(args) // 会直接报错的,因为形参是局部变量,只能函数体内用。args is not defined
return返回一个值,如果想返回多个值,用数组或对象
// 只能返回第一个,因为遇到return,就会终止函数
function fn() {
return '99'
return 0
}
console.log(fn()) // '99'
// 需要返回很多数据时,最好用对象或数组
function fun() {
return {
xx: 0,
xxx: 1,
xxxx: 2,
// ...
}
}
console.log(fun()) // {xx: 0, xxx: 1, xxxx: 2}
function f() {
return [1, { xx: 0 }, 'pink', '4']
}
console.log(f()) // [1, {…}, 'pink', '4']
return结束的是函数,break结束的是循环,contation跳出的是本次循环
// return 终止的是函数
function fn() {
let num = 10
num++
num--
return num
}
console.log(fn()) // 10
// breack 终止的循环
for (let i = 0; i < 10; i++) {
if (i === 5) {
console.log('到5就结束了')
break
}
}
// continue 跳出的是本次循环
for (let i = 0; i < 10; i++) {
if (i === 3) {
continue
}
console.log(`第${i}次执行`)
}
函数如果不确定有多少参数
- 可以用arguments,函数内置的,以伪数组形式存储,不需要写在参数里
function fn() {
console.log(arguments)
// arguments以伪数组形式进行存储
console.log(Array.isArray(arguments)) // false
// 伪数组是用不了真数组的方法的,如果我们想用真数组的方法,需要把它转成真数组(Array.from())
// arguments.forEach(item => {
// console.log(item) // 用不了真数组的方法
// })
console.log(Array.from(arguments)) // [10, 20, 30, 40, 50]
// 可以用循环正常遍历,伪数组存在length属性
for (let i = 0; i < arguments.length; i++) {
console.log(`伪数组第${i}项:`, arguments[i])
}
// 不写return,默认返回undefined
// return
}
fn(10, 20, 30, 40, 50)
- 还可以用剩余(rest)参数,需要写在参数里fun(...args){},或fun(a,b,...args){}
function fn(...args) {
// 是真数组呦
console.log(args[0]) // 10
console.log(args[1]) // 20
// ...
}
fn(10, 20, 30, 40, 50)
function fun(num1, num2, ...args) {
console.log(num1) // 10
console.log(num2) // 20
console.log(args[0]) // 30
}
fun(10, 20, 30, 40, 50)
作用域
- 分为全局作用域和局部作用域,域就是块,可以理解为代码可执行的范围,再简单理解,就是{}包住的
- 域的出现,主要是为了解决命名的问题,有效防止了命名冲突,不同域里可以写同名变量,互不影响
// 全局作用域,全局生效
let num = 100 // 全局变量
function fn() { // 全局函数
// 局部作用域,只在块(域)内生效
let num = 99 // 局部变量
console.log(num) // 99
return function () { // 局部函数
return num
}
}
// 全局函数,全局都可以进行调用
fn() // 99
let res = fn()()
console.log(res) // 99(第一个99,是外层函数打印的) 99(第二个99,是调用闭包,接收的变量值为99)
函数分为具名函数(普通函数)和匿名函数(函数表达式)
- 普通函数,具有函数提升,可以放在任何位置
// 具有函数提升
let res = fn()
console.log(res) // 99
// 普通函数
function fn() {
return 99
}
- 函数表达式,把函数用一个变量接收,必须先声明,再调用
// 函数表达式,用变量接收函数
const fn = function () {
return 100
}
console.log(fn()) // 100
const fun = () => {
return 99
}
console.log(fun()) // 99
- 还有一种特殊函数,立即执行函数(立即执行函数):末尾一定写分号(不然他会以为不是结尾,跟下面代码混一块啦)
(function(){})() ; 或 (function(){}());
- 箭头函数,本身没有this指向,会找它上一个作用域的this赋值给自身,只要第一次确认了,后面就不会变
const obj = {
name: 'zs',
sing: function () {
console.log(this) // {name: 'zs', sing: ƒ, dance: ƒ}
},
dance: () => {
console.log(this) // window
}
}
// 对象的方法,如果是普通函数,this指向对象本身
obj.sing()
// 如果是箭头函数,则指向window
obj.dance()
类与对象的关系
类是抽象的,包含了一大类,抽离了一些这一类公有的属性和行为
es6之前的类,表现形式就是构造函数
// 构造函数首字母大写,用于与普通函数做区分(推荐首字母大写)
function Person(name, age, gender) {
// 属性
this.name = name
this.age = age
this.gender = gender
// 行为
this.say = function (language) {
return '会说' + language
}
}
// 想要使用构造函数,需要new关键字
let zs = new Person('张三', 24, '男')
console.log(zs) // Person {name: '张三', age: 24, gender: '男', say: ƒ}
console.log(zs.say('中文')) // 会说中文
es6新增了类class
// 类名首字母大写
class Person {
// 属性
constructor(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
}
// 行为
say(language) {
return `会说${language}`
}
}
// 使用类,也需要new关键字,new就是new出来一个具体的,真实存在的对象
const ls = new Person('李四', 24, '男')
console.log(ls) // Person {name: '李四', age: 24, gender: '男'}
console.log(ls.say('中文')) // 会说中文
我们new一个类,就会得到一个具体的对象,对象是具体的,真真实实存在的。打个比方,例如人类,就是一个大类,类里面存放一些人类共有的属性(名词)和行为(动词),然后,我,就是一个实实在在的人,就是一个对象。通过new 人类,就会得到一个具体的对象
原型链
作用:
- 用来存放一些公用的属性和方法
谁存在原型:
- 函数与对象都是有原型的
- 函数有显示原型prototype
- 对象有隐式原型__proto__
我们new一个构造函数或者类,就会得到一个新的对象,构造函数的prototype其实就等于new出来这个对象的__proto__
图解
代码
// 构造函数
function Person(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
this.say = function (language) {
return '会说' + language
}
}
console.log(Person.prototype) // {constructor: ƒ}
console.log(Person.prototype.constructor) // 指回构造函数
console.log(Person.prototype.constructor === Person) // true
// new出来的实例化对象
const ls = new Person('李四', 24, '男')
console.log(ls.__proto__) // {constructor: ƒ}
console.log(Person.prototype === ls.__proto__) // true
console.log(ls.__proto__.constructor) // 指回构造函数
原型查找机制:
对象本身查找-->去创建当时对象的构造函数中查找-->去对象的原型中查找-->去构造函数的原型中查找-->去原型的原型中查找直到查找到null
图解
代码
// 构造函数
function Person(name, age, gender) {
this.name = name
this.age = age
this.gender = gender
this.say = function (language) {
return '会说' + language
}
}
console.log(Person.prototype) // {constructor: ƒ}
console.log(Person.prototype.constructor) // 指回构造函数
console.log(Person.prototype.constructor === Person) // true
// new出来的实例化对象
const ls = new Person('李四', 24, '男')
console.log(ls.__proto__) // {constructor: ƒ}
console.log(Person.prototype === ls.__proto__) // true
console.log(ls.__proto__.constructor) // 指回构造函数
// 但是实例化对象的隐式原型__proto__(又叫原型对象,也是个对象)也存在原型。这样一层一层往上查找,形成一条原型链,直到指向null
console.log(ls.__proto__.__proto__.__proto__) // null
原型链的最顶端是null
对象相关
遍历对象
- 推荐for...in,不能用for...of(因为对象内置没有Iterator,用不了,非要用,就手动添加Iterator)
const obj = {
name: 'zs',
age: 24,
gender: '男',
sing: function () {
return '唱'
}
}
for (const key in obj) {
console.log(key) // 对象的键名
console.log(obj[key]) // 对象的值名
}
访问对象属性
- 对象名.访问
const obj = { name: 'zs', age: 24, gender: '男', }
console.log(obj.name) // 'zs'
- 对象名['属性名'] , 对象名[变量名]访问,这种适合属性名为变量的,动态的
const obj = { name: 'zs', age: 24, gender: '男', }
// 对象名['键名']
console.log(obj['age']) // 24
// 对象名[变量名]
let key = 'gender'
console.log(obj[key]) // '男'
对象的键名是字符串,只是默认省略了。如果对象的键中有-,则就需要用引号包住啦
const obj = { name: 'zs', age: 24, gender: '男', 'sing-dance-rap': '唱跳rap' }
console.log(obj['sing-dance-rap']) // '唱跳rap'
对象中如果不存在某属性,会输出undefined
const obj = { name: 'zs', age: 24, gender: '男' }
console.log(obj.sing) // undefined
对象中不存在某属性,但是直接给这个属性赋值,则对象中就会添加此属性
const obj = { name: 'zs', age: 24, gender: '男' }
obj.sing = '唱'
console.log(obj['sing']) // 唱
in运算符
- 可以判断对象中是否存在某属性
const obj = {
name: 'zs',
age: 24,
gender: '男',
sing: function () { return '唱' }
}
console.log(name in obj) // true
// console.log(dance in obj) // 会报错
对象的一些方法
- Object.keys(对象名) 会返回对象的键组成的数组
const obj = {
name: 'zs',
age: 24,
gender: '男'
}
let keys = Object.keys(obj)
console.log(keys) // ['name', 'age', 'gender']
- Object.values(对象名) 会返回对象的值组成的数组
const obj = {
name: 'zs',
age: 24,
gender: '男',
sing: function () { return '唱' }
}
let values = Object.values(obj)
console.log(values) // ['zs', 24, '男', ƒ]
- Object.assign(对象名) 会拷贝对象,是浅拷贝
const obj = {
name: 'zs',
age: 24,
gender: '男',
sing: function () { return '唱' }
}
let newObj = Object.assign(obj)
console.log(newObj) // {name: 'zs', age: 24, gender: '男', sing: ƒ}
// 是浅拷贝
console.log(obj === newObj) // 因为地址相同,所以为true,浅拷贝
- Object.entries(对象名) 会返回对象键值对的数组
const obj = {
name: 'zs',
age: 24,
gender: '男',
sing: function () { return '唱' }
}
let keysValues = Object.entries(obj)
console.log(keysValues)
- Object.fromEntries(对象名) 可以把二维数组转换成对象,与Object.entries(对象名) 方法互逆操作
const obj = {
name: 'zs',
age: 24,
gender: '男',
sing: function () { return '唱' }
}
let keysValues = Object.entries(obj)
console.log(keysValues)
let newObj = Object.fromEntries(keysValues)
console.log(newObj) // {name: 'zs', age: 24, gender: '男', sing: ƒ}
原文链接:https://blog.csdn.net/qq_52845451/article/details/129721480
此处评论已关闭