续 : 上次练习作业
- 用户输入一个整数 n,计算 n 的阶乘。即
n*(n-1)*(n-2)*……*3*2*1 - 苹果 3 元一个, 鸭梨 2 元一个, 桃子 1 元一个。现在想用 200 元正好买 100 个水果, 用 JS 列出所有购买方案
- 在控制台输出 100~200 之间所有的质数
- 7 不是质数
- 7/1 7
- 7/7 7
- 9 是质数
- 9/1 9
- 9/3 9
- 9/9 9
- 7 不是质数
// 1. 用户输入一个整数 n,计算 n 的阶乘。即`n*(n-1)*(n-2)*……*3*2*1`
// 假设 用户输入的 7
// var num = prompt('请您输入一个数字') - 0
/**
* 逻辑:
* 假设用户输入的是 数字 7
* 1. 先拿到 7~1 的所有数字
* 2. 计算阶乘
*/
// var sum = 1
// for (var i = num; i > 0; i--) {
// // sum = sum * i
// sum *= i
// }
// console.log(sum)
// 2. 苹果 3 元一个, 鸭梨 2 元一个, 桃子 1 元一个。现在想用 200 元正好买 100 个水果, 用 JS 列出所有购买方案
/**
* 1. 需要利用分支语句, 确保总价为 200 元, 数量为 100 个
*
* 2. 假设: 苹果购买了 a 个
* 鸭梨购买了 b 个
* 桃子购买了 c 个
*
* a * 3 + b * 2 + c * 1 === 200
* a + b + c === 100
*/
// for (var a = 0; a <= 100; a++) {
// for (var b = 0; b <= 100; b++) {
// for (var c = 0; c <= 100; c++) {
// if (a * 3 + b * 2 + c * 1 === 200 && a + b + c === 100) {
// console.log(a, b, c)
// }
// }
// }
// }
// 3. 在控制台输出 100~200 之间所有的质数
/**
* 1. 判断数字 7 是不是质数
* 7 % 2 !== 0
* 7 % 3 !== 0
* 7 % 4 !== 0
* 7 % 5 !== 0
* 7 % 6 !== 0
*
*
* 2. 判断数字 9 是不是质数
* 9 % 2 !== 0
* 9 % 3 === 0
* 9 % 4 !== 0
* 9 % 5 !== 0
* 9 % 6 !== 0
* 9 % 7 !== 0
* 9 % 8 !== 0
*
* 2. 判断数字 8 是不是质数
* 8 % 1 === 0
* 8 % 2 === 0
* 8 % 4 === 0
* 8 % 8 === 0
*/
// 验证:
// var n = 7 // 判断 数字 7 是不是 质数
// var sum = 0 // 当前变量初始值给一个 0, 但不是固定的, 你可以随意给值 相当于 自己和自己的约定
// for (var i = 2; i < n; i++) {
// // if (7 % 2 !== 0) {
// if (n % i === 0) {
// // console.log('如果我输出了, 说明当前数字不是质数')
// sum++
// }
// }
// if (sum !== 0) {
// console.log('不是质数')
// } else {
// console.log('是质数')
// }
for (var n = 100; n <= 200; n++) {
var sum = 0 // 当前变量初始值给一个 0, 但不是固定的, 你可以随意给值 相当于 自己和自己的约定
for (var i = 2; i < n; i++) {
if (n % i === 0) {
sum++
}
}
if (sum === 0) {
console.log(n, '是质数')
}
}
函数
- 在 JS 中, 函数可以理解为一段 在程序中 (在当前页面) 多次出现的一段代码(多行)
- 我们可以将这一段代码 放在一个盒子中, 这个盒子就是 函数
函数的使用必须要先定义, 然后调用
- 定义:
- 分为两种方式:
- 1.1 声明式定义 function 函数名 (参数) {函数要执行的一段代码} function: 关键字, 不要拼写错了 函数名: 将来调用函数的时候需要使用, 参考变量的命名规范 (参数): 参数可写可不写, 详细的讲解, 先欠着 {}: 大括号内书写, 函数在调用的时候, 需要执行的代码
- 1.2 赋值式定义 var 变量名(函数名) = function (参数) {函数要执行的一段代码}
- 分为两种方式:
- 调用
- 注意:如果函数只有定义, 没有调用, 那么这个函数永远不会执行
- 语法:函数名()
- 假设函数名为 fn -> 调用语法: fn()
// 1. 声明式定义
// 定义解析
function fn1() {
console.log('函数调用的时候, 我会输出, 如果没有调用, 我永远不执行')
}
// 2. 调用
fn1()
// 3. 赋值式定义
var fn2 = function () {
console.log('我是 FN2 函数')
}
fn2()
函数中的参数
* 因为如果一个函数没有参数的话, 这个函数的功能十分固定
* 如果想要让一个函数更加灵活, 那么一定需要利用函数的参数
- 函数的参数其实分两个, 书写的位置不同
- 形参: function 后的小括号内书写, 书写的时候, 直接写一个 "变量名", 然后在这个函数内部, 可以使用 形参起名的时候, 参考变量的命名规范
- 实参: 函数调用时的小括号内书写的, 作用是传递给函数的形参, 给形参赋值
- 注意: 形参和实参, 都可以传递多个! 但是数量要一致
重要
- 参数的默认值
- 就在需要书写 形参的后边利用 赋值号 给这个形参一个默认值
- 在你没有传递对应的实参的时候, 形参会利用默认值
- 注意, 如果形参有对应的实参, 那么默认值不会生效
注意: 需要默认值的形参, 一般会放在函数的最后
- 就在需要书写 形参的后边利用 赋值号 给这个形参一个默认值
// 错误写法
function fn(a = '我是一个默认值', b) {
console.log(a, b)
}
fn(undefined, '当前字符串应该给到形参b')
// 正确的书写默认值
// function fn(a, b = '我是一个默认值') {
// console.log(a, b)
// }
// fn(100, 200)
当实参与形参数量不一致时
// 实参的数量 > 形参的数量; 传递的时候 实参会按照顺序依次传递给对应的形参, 多余的实参, 无法再当前函数以形参的方式去使用
// function fn(a, b) {
// console.log(a, b)
// }
// fn(100, 200, 300, 400, 500)****
// 形参的数量 > 实参的数量, 传递的时候 实参会按照顺序依次传递给对应的形参, 多余的形参, 没有值, 是 undefined
// function fn(a, b) {
// console.log(a, b)
// }
// fn(100)
// 正常书写多个参数
// function fn(a, b) {
// // var num = 1 + 1
// // console.log(num)
// console.log(a, b)
// }
// fn(100, 'str')
小练习
封装一个函数, 判断一个数字,是不是质数
function fn(num) {
// 判断一个数字是否为质数
/**
* 逻辑:
* 假设要判断的数字为 7 是一个质数
* 7 % 2 !== 0
* 7 % 3 !== 0
* 7 % 4 !== 0
* 7 % 5 !== 0
* 7 % 6 !== 0
*
* 假设要判断的数字为 8 不是质数
* 8 % 2 === 0
* 8 % 3 !== 0
* 8 % 4 === 0
* 8 % 5 !== 0
* 8 % 6 !== 0
* 8 % 7 !== 0
*/
var sum = 0
for (var i = 2; i < num; i++) {
if (num % i === 0) {
sum++
}
}
if (sum === 0) {
console.log(num, '是质数')
} else {
console.log(num, '不是质数')
}
}
fn(5)
fn(7)
fn(8)
fn(20)
函数返回值
- 每一个函数内部都有一个 return, 这个能够决定当前函数的返回值是什么,如果没有书写, 那么默认返回一个 undefined
- 函数内部如果没有书写 return, 那么函数的执行(调用)结果, 是一个 undefined
- 如果我们需要更改函数的返回值, 需要将 return 书写在函数内代码的最后
- return 具有中断函数的能力, 所以必须放最后
// function fn(a, b) {
// var sum = a + b
// return sum
// }
// var res = fn(500, 200) // 讲 fn 函数的调用结果, 赋值给 变量 res
// console.log(res)
// console.log(sum) // 函数内部创建的变量, 无法在函数外使用, 详细原因后续解释
// return
function fn() {
console.log(1)
console.log(2)
console.log(3)
console.log(4)
return 123
}
var res = fn()
console.log(res)
封装一个函数, 判断一个数字是不是质数, 根据结果返回不同的布尔值, 如果是质数, 返回一个 true, 否则返回false
小案例练习
// 封装一个函数, 判断一个数字是不是质数, 根据结果返回不同的布尔值, 如果是质数, 返回一个 true, 否则返回false
/**
* 1. 需要书写一个函数
* 2. 需要 一个 参数
* 3. 需要书写返回值
*/
function fn(num) {
var sum = 0
for (var i = 2; i < num; i++) {
if (num % i === 0) {
sum++
}
}
// if (sum === 0) {
// // console.log('是质数')
// return true
// } else {
// // console.log('不是质数')
// return false
// }
return sum === 0
}
var res = fn(7)
console.log(res) // true
var res1 = fn(9)
console.log(res1) // false
预解析
1.变量
变量提升, 其实就是在变量定义前去使用这个变量
使用 var 声明的变量, 具有变量提升的能力, 换句话说, 再定义变量前是用变量
不会报错, 但是值, 变成了 undefined
2.函数 (声明式函数)
浏览器再解析代码的时候, 会将函数提升到当前作用域(当前页面)的最顶端
// 变量
// // 1. 先使用变量
// console.log(a) // undefined
// // 2. 再定义变量
// var a = 100
/**
* 正常书写代码:
* console.log(a)
* var a = 100
*
* 浏览器预解析后的代码
* var a
* console.log(a)
* a = 100
*/
- 声明式与赋值式的区别
- 写法不同
- 赋值式不能在函数定义前去调用, 而声明式可以
- 原因:
- 赋值式是利用 变量提升
- 声明式是利用 函数提升
- 原因:
fn1()
// fn2() // undefined()
// 声明式
function fn1() {
console.log('fn1 函数')
}
// 赋值式
var fn2 = function () {
console.log('fn2 函数')
}
fn1()
fn2()
作用域
变量可以使用的范围
因为变量不是在任何地方都可以使用, 而这个能够使用的范围, 我们称之为 作用域
- 全局
- 是 JS 中 最大的一个作用域
- 在 全局作用域中, 创建的变量, 可以在任意的地方使用
- 直接写在 script 标签内的 变量, 我们称之为全局变量, 这个作用域也叫做 全局作用域
- 我们的全局作用域中有一个 浏览器帮我们生成的 对象 (一种数据类型), 叫做 window
- 我们在全局作用域声明的变量会自动添加到 window 对象中
- 局部 (函数作用域)
- 在 JS 中, 只有函数能够创建局部作用域
- 在局部作用域内创建的变量, 只能在当前作用域内使用, 超过这个作用域则不能使用
- 尽可能的多写局部变量, 不写全局变量
// var a = 100
// var a1 = '我是一个全局变量'
// console.log(window)
// alert('我是一个弹出框')
function fn() {
var str = '我是定义在 fn 函数的局部作用域内的变量, 超过这个作用域就不能使用了'
console.log(str)
}
fn()
function fn1() {
var str = '我是 fn1 函数内部的 str 我的变量名和 fn 函数内的 相同, 但是因为 作用域不同, 所以互不影响'
console.log(str)
}
fn1()
// console.log(str)
作用域链
- 是一个 纯概念性的东西
- 当我们在某一个作用域内获取一个变量的时候
-
首先在自己(当前)的作用域内查找, 找到就使用, 如果没有找到, 会去自己(当前)作用域的上层作用域(父级作用域)
-
如果在 上层作用域 找到, 直接使用, 并停止查找, 如果没有找到, 那么继续向上层查找
-
如果上层作用域也没有找到, 那么会继续去上层作用域找, 直到找到全局作用域, 如果还没有找到, 此时报错
- 上述的也叫做 访问规则; 重点, 变量在访问的时候, 会顺着作用域 逐层向上查找, 不会逐层向下查找
-
赋值规则:
- 如果再给一个变量赋值的时候, 首先会在当前作用域内查找这个变量
- 如果没有找到, 那么回去上层作用域查找, 如果还没有, 继续向上
- 直到找到了全局作用域也没有找到, 在全局创建一个变量, 并赋值
var a = 1
function fn () {
var a = 2
function fn1 () {
var a = 3
console.log('fn1', a)
}
fn1()
console.log('fn', a)
}
fn()
// 赋值规则
// function fn() {
// a = 100
// console.log(a) // 100
// }
// fn()
// console.log(a) // 100
// function fn1 () {
// a = 1
// }
// fn1()
// console.log(a) // 1
// 访问规则
// var a = 'QF666'
// function fn() {
// function fn1() {
// var a = 100
// }
// fn1()
// console.log(a)
// }
// fn()
// 作用域链
// var a = 10
// function fn () {
// function fn1 () {
// console.log(a)
// }
// fn1()
// }
// fn()