文章目录
一、JavaScript基础
函数
函数的声明
/** * function 函数名(参数列表) { * 函数体 * } * * 调用方法没有传入实参时,则默认形参为 undefined * * 合理利用逻辑中断 * 形参如果不被赋值,就是undefined */ function getSum(Start, end) { Start = Start || 0 // 调用方法没有传入实参时,默认形参为0 end = end || 0 let sum = 0 for (let i = Start; i <= end; i++) { sum += i } console.log(sum) }
注意点
两个相同的函数后面的会覆盖前面的函数
函数的传参
术语1:
在声明函数的小括号里面写的数值我们称之为形式参数
术语2:
在调用函数的小括号里面写的数值我们称之为实际参数
形参作用:
本质上就是在函数内部声明变量补充
在Javascript中 实参的个数和形参的个数可以不一致
①如果形参过多 会自动填上undefined (了解即可)
②如果实参过多 那么多余的实参会被忽略 (函数内部有一个arguments,里面装着所有的实参)function fnOne(x, y) { console.log(arguments) // x = 1 // y = undefined // 1 + undefined = NaN console.log('fnOne', x + y) } fnOne(1, 2) // 3 // 1. 实参个数少于形参 函数执行失败 返回的结果:NaN fnOne(1) // NaN /* 2. 实参个数大于形参 函数能执行成功 * 实参存入 arguments 数组 * arguments:函数内有效 * 表现形式:伪数组 * 伪数组 比真数组少了 pop() push() 等方法 */ fnOne(1, 2, 3) // 返回的结果:3 /***************** 小技巧 *****************/ function fnTwo(x = 0, y = 0) { console.log(arguments) console.log('fnTwo', x + y) } fnTwo() // 0
函数的调用和返回值
/********************* 多个返回值 *********************/ // 求最大值和最小值 function getArrMaxValue(arr) { let max = arr[0] let min = arr[0] for (let i = 1; i < arr.length; i++) { max < arr[i] ? max = arr[i] : min > arr[i] ? min = arr[i] : min } // 返回这个最大值和最小值 return [max, min] } let maxMin = getArrMaxValue([1, 6, 2, 9, 3]) // [9, 1] let max = maxMin[0] let min = maxMin[1] console.log('maxMin', maxMin) console.log('max', max) console.log('min', min)
函数表达式
一、匿名函数
将匿名函数赋值给一个变量,并且通过变量名称进行调用,我们将这个称为函数表达式let fn02 = function (x, y) { console.log(x + y) } fn02(1, 2)
二、自执行(匿名函数自执行)
场景介绍: 避免全局变量之间的污染/***************** 使用函数表达式-立即执行函数 *****************/ // 写法一 (function () {})() (function () { console.log(num) })(); // 写法二 (function () {}()) (function (x, y) { console.log(x + y) }(1, 2)); // 特殊情况 及时给出名字,也会被立即执行 (function fn(x, y) { console.log(x + y) }(1, 2))
作用域
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
全局作用域 局部作用域 块级作用域 全局有效 局部有效 {}内有效 作用于所有代码执行的环境(整个script标签内部)或者一个独立的js文件 作用于函数内的代码环境,就是局部作用域。因为跟函数有关系,所以也称为函数作用域。函数内部的形参可以当做局部变量 块作用域由{}包括,if语句和for语句里面的{}等 有一种特殊情况是全局变量
局部变量或者块级变量没有 let 声明,直接赋值的,当全局变量看 【强烈不提倡】
全局变量 局部变量 块级变量 函数外部let的变量 函数内部let的变量 {}内部的let变量 全局变量在任何区域都可以访问和修改 局部变量只能在当前函数内部访问和修改 let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访
环境对象
环境对象指的是函数内部特殊的变量this,它代表着当前函数运行时所处的环境
作用:
弄清楚this的指向,可以让我们代码更简洁
函数的调用方式不同,this指代的对象也不同
【谁调用, this 就是谁】是判断this指向的粗略规则
函数进阶
函数的声明方式
// 函数声明方式 function 关键字 (命名函数) function fn() {} // 函数表达式 (匿名函数) let fun = function() {} // new Function('参数1','参数2'..., '函数体') let f = new Function('a', 'b', 'console.log(a+b)') f(1, 2) // 所有函数都是 Function 的实例(对象) console.dir(f);
函数的调用方式
// 普通函数 function fn() { console.log('人生的巅峰') } fn() // 对象的方法 let o = { sayHi: function () { console.log('人生的巅峰'); } } o.sayHi() // 构造函数 function Star() {} let star = new Star() // 绑定事件函数 btn.addEventListener('click', function () {}) // 定时器函数 setInterval(function() {}, 1000) // 立即执行函数 (function () { console.log('人生的巅峰') })();
改变环境变量
/** * call() 方法调用一个对象。简单理解为调用函数的方式,但是它可以改变函数的 this 指向 * fun.call(thisArg, arg1, arg2, ...) * thisArg:在 fun 函数运行时指定的 this 值 * arg1,arg2:传递的其他参数 * 返回值就是函数的返回值,因为它就是调用函数 * 因此当我们想改变 this 指向,同时想调用这个函数的时候,可以使用 call,比如继承 */ /** * apply() 方法调用一个函数。简单理解为调用函数的方式,但是它可以改变函数的 this 指向 * fun.apply(thisArg, [argsArray]) * thisArg:在fun函数运行时指定的 this 值 * argsArray:传递的值,必须包含在数组里面 * 返回值就是函数的返回值,因为它就是调用函数 * 因此 apply 主要跟数组有关系,比如使用 Math.max() 求数组的最大值 */ let arr = [1, 2, 3, 4, 5] let max = Math.max.apply(Math, arr) console.log(max); /** * bind() 方法不会调用函数。但是能改变函数内部this 指向 * fun.bind(thisArg, arg1, arg2, ...) * thisArg:在 fun 函数运行时指定的 this 值 * arg1,arg2:传递的其他参数 * 返回由指定的 this 值和初始化参数改造的原函数拷贝 * 因此当我们只是想改变 this 指向,并且不想调用这个函数的时候,可以使用 bind */
高阶函数
函数表达式
把函数当值赋值给变量
回调函数
把一个函数作为参数传递给另外一个函数
递归函数
利用递归函数求斐波那契数列
// 利用递归函数求斐波那契数列(兔子序列) 1、1、2、3、5、8、13、21... // 用户输入一个数字 n 就可以求出 这个数字对应的兔子序列值 // 我们只需要知道用户输入的n 的前面两项(n-1 n-2)就可以计算出 n 对应的序列值 function fb(n) { if (n === 1 || n === 2) { return 1; } return fb(n - 1) + fb(n - 2); } console.log(fb(6)); // 8
利用递归遍历数据
let data = [ { id: 1, name: '家电', goods: [ { id: 11, goodName: '冰箱', goods: [ { id: 111, goodName: '海尔' }, { id: 112, goodName: '美的' } ] }, { id: 12, goodName: '洗衣机' } ] }, { id: 2, name: '服饰' } ] function getGoodById(data, id) { let obj = {} data.forEach(function (value) { if (value.id === id) { obj = value } else if (value.goods && value.goods.length) { obj = getGood(value.goods, id) } }) return obj } console.log(getGoodById(data, 1)) console.log(getGoodById(data, 11)) console.log(getGoodById(data, 111))
对象
声明对象的语法
1、我们把冒号左边的内容称之为属性, 右边称之为值, 成对出现, 故称之为键值对
2、当右边的值为函数的时候, 我们将这个属性称之为方法
3、对象本质是一种无序的数据集合, 对比数组来说它里面装的都是不同类型的数据, 并且有对应的属性提示数据的含义
4、对象访问属性的方式
①对象.属性名
②对象[‘属性名’]/** * 对象有属性和方法组成 * let 对象名= { * 属性名:属性值, * 方法名:函数 * } */ let phone = { name: '小米10青春版', num: '100012816024', weight: '0.55kg', address: '中国大陆', sayHey: function () { console.log("Hello js!") } } // 输出对象 console.dir('phone', phone) // 1.访问对象里面的属性 对象.属性名 console.log('phone.name', phone.name) // 2.访问对象里面的属性 对象[属性名] console.log('phone.name', phone['name']) // 3.访问对象里面的方法 对象.方法名() phone.sayHey()
使用对象
操作数据的增删改查语法:
查询对象:
对象.属性
对象.[‘属性’]
对象.方法()
重新赋值:
对象.属性 = 值
对象.方法 = function(){}
对象添加新的数据:
对象名.新属性名 = 新值
删除对象中属性:
delete 对象名.属性名let obj = { username: '小明', age: 18 } // 修改属性值 obj.age = 21 // 新增属性 obj.sex = '男' // 删除属性 delete obj.sex
遍历对象
引入[]语法操作对象属性
对比点语法的相同点和不同点
都可以访问对象的属性 对象名.属性名 === 对象名[‘属性名’]
[]语法里面的值如果不添加引号 默认会当成变量解析
没有必要的时候直接使用点语法, 在需要解析变量的时候使用 [] 语法
遍历对象
对象没有length属性,所以无法确定长度
对象里面是无序的键值对, 没有规律let phone = { name: '小米10青春版', num: '100012816024', weight: '0.55kg', address: '中国大陆' } // 遍历对象的属性值 for (let phoneKey in phone) { // phoneKey 变量名 console.log(phoneKey, phone[phoneKey]) // 不能使用phone.phoneKey }
内置对象
console.log(Math.random()) // 随机数 console.log(Math.ceil(1.66)) // 2 向上取整 console.log(Math.floor(1.66)) // 1 向下取整 console.log(Math.round(1.33)) // 1 就近取整 四舍五入 console.log(Math.round(1.5)) // 2 console.log(Math.round(-1.5)) // -1 特殊(.5往大取整) console.log(Math.round(1.66)) // 2 console.log(Math.max(1.66, 1.56, 2.999)) // 找最大数 Math.floor(Math.random() * (10 + 1)) // 生成0-10的随机数 Math.floor(Math.random() * (5 + 1)) + 5 // 生成5-10的随机数 Math.floor(Math.random() * (M + N + 1)) + N // 生成N-M之间的随机数
操作对象(进阶&积累)
①封装对象自身所有的属性
let obj = {id: 1, pName: '小米', price: 1999, num: 2000} let arrKeys = Object.keys(obj); /** 返回一个由属性名组成的数组 */ let arrValues = Object.values(obj) /** 返回一个由属性值组成的数组 */ console.log(arrKeys) // ['id', 'pName', 'price', 'num'] console.log(arrValues) // [1, '小米', 1999, 2000]
②浅拷贝
Object.assign(objNew,objOld)
③定义新属性或修改原有的属性
let obj = {id: 1, pName: '小米', price: 1999} Object.defineProperty(obj, 'num', { /* 设置属性的值 默认为undefined value: 1000, /** 值是否可以重写。true | false 默认为false */ writable: false, /** 目标属性是否可以被枚举。true | false 默认为 false */ enumerable: false, /** 目标属性是否可以被删除或是否可以再次修改特性 true | false 默认为false */ configurable: false }); console.log(Object.keys(obj)); // ['id', 'pName', 'price']