041 嵌套 for循环
例:输出金字塔
*
* *
* * *
* * * *
* * * * *
代码
for (let i = 0; i < 5; i++) {
for (let j = 0; j <= i; j++) {
document.write("* ");
}
document.write("<br />");
}
042-043 for循环练习
练习:打印九九乘法表
<script>
for (let i = 1; i <= 9; i++) {
for (let j = 1; j <= i; j++) {
document.write("<span>" + j + "*" + i + "=" + (j*i) + "</span>");
}
document.write("<br />")
}
</script>
<style type="text/css">
body {
width: 2000px;
}
span{
display: inline-block;
width: 80px;
}
</style>
练习:打印1-100间所有质数
for (let i = 2; i <= 100; i++) {
let flag = true;
let limit = Math.sqrt(i);
for (let j = 2; j <= limit; j++) {
if (i % j == 0) {
flag = false;
break;
}
}
if (flag) {
console.log(i);
}
}
044 break 和 continue
break
break:跳出 switch 或循环;不能用于 if;立即终止所处的循环
跳出多重循环:可以先给循环体取名来标识当前循环
outer:
for (let i = 0; i < 5; i++) {
console.log("@外层循环" + i);
for (let j = 0; j < 5; j++) {
break outer;
console.log("内层循环:" + j);
}
}
continue
continue:跳过本次循环,从循环体开始位置执行
性能测试
console.time("test");
// 执行的程序
console.timeEnd("test");
045 质数练习的改进
通过 Math.sqrt()
对一个数进行开方
046 对象简介
基本数据类型都是单一的值(如 "hello", 123, true
),值与值之间没有联系
Object 对象,属于复合数据类型,在对象中可以保存多个不同数据类型的属性
对象的分类
- 内建对象
- ES 标准定义的对象,任何的ES实现都可以使用
- 例:Math, String, Number, Boolean, Function, Object...
- 宿主对象
- JS 的运行环境提供的对象,主要指浏览器提供的对象
- 例:BOM, DOM
- 自定义对象
- 开发者自己创建的对象
047 对象的基本操作
创建对象
new 关键字调用的函数,是构造函数 constructor
构造函数是专门用于创建对象的函数
使用 typeof 检查对象会返回 object
let obj = new Object();
添加 / 修改属性
对象.属性名 = 值
obj.name = "Me";
obj.gender = "male";
obj.age = 18;
读取属性
对象.属性名
console.log(obj.name);
// console.log(name); 会报错
如果读取对象中没有的属性,不会报错,而是返回 undefined
删除属性
delete 对象.属性
delete obj.name;
048 属性名和属性值
属性名:不强制要求遵守标识符规范,但是尽量按照标识符
特殊属性名:需要用中括号,对象["属性名"] = 属性值
obj["123"] = "hello";
属性值:可以是任意数据类型(包括 Object,甚至可以是对象自己)
检测是否有属性:in
运算,检查一个对象中是否有指定属性
console.log("test" in obj);
049 基本数据类型和引用数据类型
基本数据类型:String, Number, Boolean, Null, Undefined
引用数据类型:Object
JS 基本数据类型直接在栈内存中,值与值独立存在,修改一个变量不会影响其他变量
let a = 123;
let b = a;
a++;
console.log(b); // 123
引用数据存储在堆内存中,栈内存中保存的是内存地址(变量的引用),修改一个地址的变量会影响所有该地址的引用
let obj1 = {name : "123"};
let obj2 = obj;
obj1.name = "456";
console.log(obj2.name); // 456
obj2 = null; // 不影响 obj1
let obj3 = {name: "789"};
let obj4 = {name: "789"};
console.log(obj3 == obj4); // false
050 对象字面量
let obj = {
name: "123",
age: 28,
gender: "male",
test: {
name: "456"
}
};
属性名实际上是字符串,可以加引号,也可以不加(特殊属性名必须加字符串)
属性名和属性值是成对的,名和值之间用 : 连接
051 函数的简介
函数也是对象,一切东西都是对象
函数中可以封装一些功能(代码),在需要时可以执行
可以将要封装的代码以字符串形式传递给构造函数
Function 对象
let fun1 = new Function("alert('Hello world');");
console.log(typeof fun1); // function
封装到函数的代码不会立即执行,在调用函数时才会执行
fun1();
函数声明
实际开发中很少使用 Function()
,而是使用函数声明
function 函数名([形参1, 形参2,..., 形参n]) {
代码
}
例
function fun2() {
console.log("执行 fun2");
alert("6");
document.write("7");
}
fun2();
函数表达式
函数表达式会生成匿名函数
let fun3 = function() {
alert("9");
}; // 注意这是赋值语句,所以要有分号
052 函数的参数
调用函数时,可以在()
中指定实参,实参会赋值给函数中对应的形参
function sum(a, b) {
console.log(a + b);
}
sum(1, 2);
sum(123, 456);
调用函数时不会检查实参类型,所以要注意非法输入
sum(123, "hello"); // 123hello
调用函数时也不会检查实参数量,多余的实参不会赋值,少的实参是 undefined;
sum(1, 2, 3); // 1 + 2 -> 3
sum(123); // 123 + undefined -> NaN
053 函数的返回值
使用 return 设置函数返回值
function sum(a, b) {
return a + b;
}
let result = sum(1, 2);
console.log(result); // 3
return 后的语句都不会执行
return 后不跟任何值,或者函数无 return,则返回 undefined
let result = alert("6");
console.log(result); // undefined
054 实参可以是任何值
实参可以是对象;参数过多时可以将参数封装到对象中
function sum(obj) {
return obj["first"] + obj["second"];
}
实参可以是函数
function hello() {
console.log("Hello");
}
function fun(a) {
a();
}
fun(hello);
fun(function(){alert("6")});
注意函数对象与函数返回值的区别
fun(sum); // 传的是函数对象
fun(sum()); // 传的是返回值
055 返回值的类型
返回值可以是任何类型
函数内部可以声明函数,返回函数
function fun1(a) {
function fun2(b) {
return a + b;
}
return fun2;
}
let a = fun1(1);
let b = a(2); // 1 + 2 == 3
fun1(1)(2); // 3
056 立即执行函数
函数定义完,立即执行
// 无参数例子
(function() {
alert("6");
})()
// 有参数例子
(function(a, b) {
console.log(a + b);
})(1, 2);
057 方法
函数作为对象属性,就称为对象的方法,调用函数就称为调用方法(method);函数与方法只是名称的区别
let obj = {};
obj.name = "123";
obj.age = 18;
obj.getName = function() {
console.log(obj.name);
}
obj.getName();
枚举对象中的属性:for-in 语句,每次将一个属性名赋值给变量
for (let n in obj) {
console.log(n); // 输出属性名
console.log(obj[n]); // 输出属性值
}
058 全局作用域
JS 作用域有两种:全局作用域,函数作用域(局部作用域)
全局作用域
- 直接编写在 script 标签的 JS 代码都在全局作用域
- 全局作用域在页面打开时创建,关闭时销毁
- 全局作用域中有一个全局对象 window,代表浏览器窗口可以直接使用
- 全局作用域中创建的变量都会作为 window 对象的属性,函数都会作为 window 对象的方法
- 变量与函数声明
- 使用 var 声明的变量会在所有代码之前声明,但只有执行到这一行才赋值
- 使用函数声明形式函数会在所有代码之前创建,写在任何位置都是一样的
- 使用函数表达式的函数不会被提前创建
- 全局作用域的变量都是全局变量
059 函数作用域(局部作用域)
函数作用域
- 调用函数时创建函数作用域,执行完毕后作用域销毁
- 每调用一次函数会创建一个新的函数作用域,不同的函数作用域相互独立
- 函数作用域可以调用全局变量,全局中不能访问函数作用域的变量
- 在函数作用域操作变量时,会先在作用域中找,如果未找到会向上一级作用域中寻找;如果仍未找到会报错 ReferenceError
- 函数作用域的变量
- 使用 var 声明的变量会在函数代码执行前声明;
- 不使用 var 则会变成全局变量
- 形参相当于函数作用域变量
使用 let 声明的变量都是局部变量
060 debug
如何 debug(以 Chrome 为例)
按 F12 打开开发者模式,切换到 Sources 页面
切换到 Page 找到页面源代码,在行数左侧点击以设置断点
在 Scope 中可以观察到全部变量,Watch 可以添加监控