一.类型转换
1.1 数字类型转换为字符串类型(三种方式)
let a = 10;
console.log(a.toString()) //'10'
console.log(String(a))//'10'
console.log(a + '') //隐式转换 + 字符串 ,'10'
1.2.字符串类型转换为数字类型(四种方式)
let a = '10'; b = '3.14'; c = '120px1';
console.log(parseInt(a)); // 10
console.log(parseInt(b)); // 3 //parseInt只能转换成整数类型
console.log(parseInt(c)); // 120
console.log(parseFloat(a)); // 10
console.log(parseFloat(b)); // 3.14 //将string类型转换成浮点类型
console.log(parseFloat(c)); // 120
console.log(Number(a)); // 10
console.log(Number(b)); // 3.14
console.log(Number(c)); // NAN
console.log(a - 0); //10
console.log(a - '1'); // 9 //隐式转换 - 字符串
console.log(a * 1); // 10 //隐式转换 * 字符串
console.log(a * '1'); // 10
1.3.转换为布尔值,代表为空 否定的值都换转换成false 如:'', 0, NaN, null undefined
console.log(Boolean('')); //false
console.log(Boolean(0)); //false
console.log(Boolean(NaN)); //false
console.log(Boolean(null)); //false
console.log(Boolean(undefined)); //false
二.运算符
2.1浮点数精度有问题
console.log(0.1 + 0.2) // 浮点数精度有问题0.30000000000000004
console.log(0.07 + 100) //100.07
let num = 0.1 + 0.2
console.log(num === 0.3) // false
2.2 前置递增 ++a,后置递增 a++
// 前置递增 ++a
let a = 1
++a // a = a+ 1
console.log(a) // 2
let p = 10
console.log(++p + 10) // 21 口诀:先自加 再返回值
// 后置递增 a++
let a = 1
a++ // a = a+ 1
console.log(a) //2 如果单独使用前置递增和后置递增效果是一样的
let p = 10
console.log(p++ + 10) // 20 口诀:先返回原值 再自加
2.3 ==(会转型)默认会转型 只要求两边的值一样,===两边的值和数据类型都一样
console.log(18 == '18') //true 默认会转型 只要求两边的值一样
console.log(18 === '18') //false 两边的值和数据类型都一样
2.4 逻辑中断逻辑与 &&
// 1.用布尔值参与的逻辑运算
console.log(4 > 2 && 3 > 2) //true
// 2.如果是值或者表达式参加的逻辑与运算 如果表达式1为真 则返回表达式2;表达式1为假 则返回表达式1
console.log(123 && 345) // 345
console.log(0 && 4) // 0
console.log(0 && 4 + 1) // 0
2.5 逻辑中断逻辑或 ||
// 1.用布尔值参与的逻辑运算
console.log(4 > 2 || 3 > 2) //true
// 2.如果是值或者表达式参加的逻辑或运算 如果表达式1为真 则返回表达式1;表达式1为假 则返回表达式2
console.log(123 || 345) // 123
console.log(0 || 4) // 4
console.log(0 || 4 + 1) // 0
let num = 10
console.log(123 || num++) //123 逻辑中断不会执行num++
console.log(num) // 10
三 函数
3.1编译型语言和解释型语言
3.2 函数声明
函数声明:1.利用关键字声明function 2.函数表达式(匿名函数) var fun =function{} fun是一个变量
3.3 作用域
作用域:变量在某个范围内起作用和效果,目的是为了提高代码的可读性,重要的是减少命名冲突
全局作用域 局部作用域 块级作用域{}
全局变量和局部变量对比:执行效率(1)全局变量只有浏览器关闭的时候才会销毁,比较占内存资源(2)局部变量当我们程序执行完毕就会销毁,比较节约内存资源
var num1 = 10 // 全局变量是在全局生效
function fun() {
var num2 = 20
num3 = 30
console.log(num1) // 10 全局生效
console.log(num2) // 20
console.log(num3) //30
}
fun()
// console.log(num2) // 局部变量只在局部有效 num2 is not defined
console.log(num3) // 30 没有声明的变量直接赋值,也是全局变量
3.4 剩余参数..args和arguments(获取所有实参是伪数组 1.有length2.有index3.没有push方法)
function sum(first, ...args) {
console.log(first); // 10
console.log(Array.isArray(args)) // true 即使没有参数也是数组
console.log(args.length); //0
}
sum()
function sum1(first, ...args1) {
console.log(arguments) //[10, 20, 30]伪数组
console.log(arguments.length) //3
console.log(arguments[0]) //10
console.log(first); // 10
console.log(Array.isArray(args1)) // true 即使没有参数也是数组
console.log(args1.length); //2
}
sum1(10, 20, 30)
3.5 普通函数和箭头函数的区别
function fn() {
console.log(arguments)
}
let fn1 = (...args) => {
console.log(args);
// console.log(arguments) //箭头函数无arguments
}
console.dir(fn)
console.dir(fn1) // 箭头函数没有prototype
fn(1, 2)
fn1(1, 2)
let obj = { name: '123' }
function test() {
console.log(this) // 指向obj
return () => {
console.log(this) //箭头函数无this指向,此时this指向obj
}
}
let res = test.apply(obj)
res()
// 箭头函数面试题
// 前提学习
let name = 'cookie'
console.log(this.name); // 输出空
console.log(this) // 可以看到name:'' ,说明let定义的不能通过this.name获取
var name1 = 'cookie1'
console.log(this.name1) // 输出cookie1
console.log(this) //name1:'cookie1',说明var定义的可以通过this.name1获取
// var age = 30
let obj = {
age: 20,
say: () => {
console.log(this.age) // undefined 因为obj是对象不能产生作用域,obj则指向的是window
}
}
obj.say()
3.6 js运行机制
js运行机制 js引擎分两步1.预解析var function提升到当前作用域最前面 2.代码执行
(1)变量提升 只提升变量 不提升赋值操作 (2)函数提升
案例1
console.log(num) //undefined
var num = 2
// 类似以下代码
var num;
console.log(num)
num = 2
案例2
fun() //报错
var fun = function () {
console.log(2)
}
// 类似以下代码
var fun;
fun() // 所以报错
fun = function () {
console.log(2)
}
// 案例3
var num = 10;
fun()
function fun() {
console.log(num) // undefined
var num = 20
}
// js引擎解析后代码
var num;
function fun() {
var num; // 变量提升到当前作用域最前面 然后根据作用链域读取值
console.log(num)
num = 20
}
num = 10;
fun()
// 案例4
var num = 10;
function fun() {
console.log(num) // undefined
var num = 20
console.log(num) //20
}
fun()
// 案例5
var a = 18;
fun()
function fun() {
var b = 9;
console.log(a) // undefined
console.log(b) // 9
var a = '123'
}
// js引擎解析后代码
var a;
function fun() {
var b;
var a;
b = 9
console.log(a) //
console.log(b)
a = '123'
}
a = 18
fun()
// 案例6
fun()
console.log(c) //9
console.log(b) //9
console.log(a) //报错
function fun() {
var a = b = c = 9; // 相当于var a=9; b=9; c = 9 b和c直接赋值的当全局变量看 , //集体声明var a =9,b=9,c=9;
console.log(a) //9
console.log(b) //9
console.log(c) //9
}
js引擎解析后代码
function fun() {
var a;
a = b = c = 9
console.log(a) // 9
console.log(b) //9
console.log(c)
}
fun()
console.log(c)
console.log(b)
console.log(a)
3.7 事件委托
事件委托原理 不是每个子节点单独设置事件监听器,而是是事件监听器设置在其父节点,然后利用冒泡原理影响设置每个子节点
事件委托的作用 只操作了一次dom 提高了性能
var ul = document.querySelector('ul')
ul.addEventListener('click', function (e) {
console.log(e)
alert(e.target.innerHTML)
e.target.style.backgroundColor = 'pink' // 点击后变色
})
阻止冒泡
<style>
div {
margin: 10px 0;
}
</style>
<div onclick="fa()">
<div onclick="test1()">1</div>
<div onclick="test2()">2</div>
</div>
<script>
function test1(e) {
console.log('test1');
}
function test2(e) {
window.event ? window.event.cancelBubble = true : e.stopPropagation(); //阻止冒泡
console.log('test2');
}
function fa() {
console.log('fa')
}
</script>