JavaScript (简称 JS)
脚本语言
, 通过解释器运行JavaScript 的能做的事情:
网页开发(更复杂的特效和用户交互)
网页游戏开发
服务器开发(node.js)
桌面程序开发(Electron, VSCode 就是这么来的)
手机 app 开发
浏览器分成渲染引擎 + JS 引擎.
渲染引擎
: 解析 html + CSS, 俗称 “内核”JS 引擎:
也就是 JS 解释器. 典型的就是 Chrome 中内置的 V8,JS 引擎逐行读取 JS 代码内容, 然后解析成二进制指令, 再执行.光有 JS 语法, 只能写一些基础的逻辑流程.
但是要想完成更复杂的任务, 完成和浏览器以及页面的交互, 那么久需要 DOM API 和 BOM API.
这主要指在浏览器端运行的 JS. 如果是运行在服务端的 JS , 则需要使用 node.js 的 API, 就不太需要关注 DOM 和 BOM
重要概念: ECMAScript
这是一套 “标准”, 无论是啥样的 JS 引擎都要遵守这个标准来实现.
直接嵌入到 html 元素内部
写到 script 标签中
HTML嵌入JavaScript的第二种方式
写到单独的 .js 文件中
HTML中嵌入JavaScript的第三种方式
// 弹出一个输入框
prompt("请输入您的姓名:");
弹出一个警示对话框, 输出结果
在控制台打印一个日志(供程序员看)
// 向控制台输出日志
console.log("这是一条日志");
注意: 在 VSCode 中直接输入 “log” 再按 tab 键, 就可以快速输入 console.log
重要概念:
console 是一个 js 中的 “对象”
. 表示取对象中的某个属性或者方法. 可以直观理解成 “的”
console.log 就可以理解成: 使用 “控制台” 对象 “的” log 方法.
虽然我们的JS跟我们的Java没有必然的联系,但是在代码编写的时候,有很多相似的地方,我们只需要了解一些JS跟Java的不同的地方
创建变量(变量定义/变量声明/变量初始化)
var name = 'zhangsan';
var age = 20;
我们的JavaScript和Java不一样的是,JS是弱类型语言,简单来说就是变量没有类型,常量值有类型
使用例子
var name = prompt("请输入姓名:");
var age = prompt("请输入年龄:");
var score = prompt("请输入分数");
alert("您的姓名是: " + name + "\n" + "您的年龄是: " + age + "\n" + "您的分数是: " +
score + "\n");
JS 的变量类型是程序运行过程中才确定的(运行到 = 语句才会确定类型)
var a = 10; // 数字
var b = "hehe"; // 字符串
随着程序运行, 变量的类型可能会发生改变.
var a = 10; // 数字
a = "hehe"; // 字符串
这一点和 C Java 这种静态类型语言差异较大.
C, C++, Java, Go 等语言是静态类型语言. 一个变量在创建的时候类型就确定了, 不能在运行时发生改变.如果尝试改变, 就会直接编译报错
局部变量和全局变量
JS 中内置的几种类型
JS 中不区分整数和浮点数, 统一都使用 “数字类型” 来表示. 0,-1,123,…小数,复数,
var a = 1;
var a = 07; // 八进制整数, 以 0 开头
var b = 0xa; // 十六进制整数, 以 0x 开头
var c = 0b10; // 二进制整数, 以 0b 开头
特殊的数字值
Infinity: 无穷大, 大于任何数字. 表示数字已经超过了 JS 能表示的范围.
-Infinity: 负无穷大, 小于任何数字. 表示数字已经超过了 JS 能表示的范围.
NaN,表示Not a Number不是一个数字,但是属于Number类型。
var max = Number.MAX_VALUE;
// 得到 Infinity
console.log(max * 2);
// 得到 -Infinity
console.log(-max * 2);
// 得到 NaN
console.log('hehe' - 10);
注意:
基本规则
字符串字面值需要使用引号引起来, 单引号双引号均可
var a = "haha";
var b = 'hehe';
var c = hehe; // 运行出错
当字符串本身存在引号
var msg = "My name is "zhangsan""; // 出错
var msg = "My name is \"zhangsan\""; // 正确, 使用转义字符. \" 来表示字符串内部的引号.
var msg = "My name is 'zhangsan'"; // 正确, 搭配使用单双引号
var msg = 'My name is "zhangsan"'; // 正确, 搭配使用单双引号
一些转义字符
有些字符不方便直接输入, 于是要通过一些特殊方式来表示.
创建字符串对象的方式
在boolean类型中有一个Boolean()函数,会将非boolean类型,转换成boolean类型。
console.log(true + 1);
console.log(false + 1)
如果一个变量没有被初始化过, 结果就是 undefined, 是 undefined 类型
var a;
console.log(a)
undefined 和字符串进行相加, 结果进行字符串拼接
console.log(a + "10"); // undefined10
undefined 和数字进行相加, 结果为 NaN
console.log(a + 10);
null 表示当前的变量是一个 “空值”.
var b = null;
console.log(b + 10); // 10
console.log(b + "10"); // null10
注意:
undefined == null 得到true
undefined === null 得到false
NaN 不等于任何数据,包括它自己
NaN == NaN 永远都是false
那么如何判断是否为NaN?isNaN(数据)如果是NaN得到true 否则得到false
JS中的和=的比较
0=="0"//true
0==="0"//false
其他的运算符和条件判断符的用法跟Java是差不多的
使用 new 关键字创建
// Array 的 A 要大写
var arr = new Array();
使用字面量方式创建 [常用]
var arr = [];
var arr2 = [1, 2, 'haha', false]; // 数组中保存的内容称为 "元素"
注意: JS 的数组不要求
元素是相同类型.
这一点和 C, C++, Java 等静态类型的语言差别很大. 但是 Python, PHP 等动态类型语言也是如此.
使用下标的方式访问数组元素(从 0 开始)
var arr = ['小猪佩奇', '小猪乔治', '小羊苏西'];
console.log(arr);
console.log(arr[0]);
console.log(arr[1]);
console.log(arr[2]);
arr[2] = '小猫凯迪';
console.log(arr);
如果下标超出范围读取元素, 则结果为 undefined
console.log(arr[3]); // undefined
console.log(arr[-1]); // undefined
注意: 不要给数组名直接赋值, 此时数组中的所有元素都没了.
var arr = ['小猪佩奇', '小猪乔治', '小羊苏西'];
arr = '小猫凯迪';
通过修改 length 新增
相当于在末尾新增元素. 新增的元素默认值为 undefined
var arr = [9, 5, 2, 7];
arr.length = 6;
console.log(arr);
console.log(arr[4], arr[5]);
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xl96MR4N-1670257665700)(JavaScript基础.assets/image-20221205192828555.png)]
通过下标新增
如果下标超出范围赋值元素, 则会给指定位置插入新元素
var arr = [];
arr[2] = 10;
console.log(arr)
使用push()新增
var arr = [9, 5, 2, 7, 3, 6, 8];
var newArr = [];
for (var i = 0; i < arr.length; i++) {if (arr[i] % 2 != 0) {newArr.push(arr[i]);}
}
console.log(newArr);
unshift()
使用 splice 方法删除元素
var arr = [9, 5, 2, 7];
// 第一个参数表示从下表为 2 的位置开始删除. 第二个参数表示要删除的元素个数是 1 个
arr.splice(2, 1);
console.log(arr);
// 结果
[9, 5, 7]
使用pop()方法删除元素
使用shift()方法删除元素
// 创建函数/函数声明/函数定义
function 函数名(形参列表) {函数体
return 返回值;
}
// 函数调用
函数名(实参列表) // 不考虑返回值
返回值 = 函数名(实参列表) // 考虑返回值
function hello() {console.log("hello");
}
// 如果不调用函数, 则没有执行打印语句
hello();
函数的定义和调用的先后顺序没有要求
. (这一点和变量不同, 变量必须先定义再使用)实参和形参之间的个数可以不匹配. 但是实际开发一般要求形参和实参个数要匹配
function sum(var x,var y) {return x+y;
}
如果实参个数比形参个数多, 则多出的参数不参与函数运算
sum(10, 20, 30); // 30
如果实参个数比形参个数少, 则此时多出来的形参值为 undefined
sum(10); // NaN, 相当于 num2 为 undefined
另外一种函数的定义方式
var add = function() {var sum = 0;for (var i = 0; i < arguments.length; i++) {sum += arguments[i];}return sum;
}
console.log(add(10, 20)); // 30
console.log(add(1, 2, 3, 4)); // 10
console.log(typeof add); // function
某个标识符名字在代码中的有效范围.
在 ES6 标准之前, 作用域主要分成两个
// 全局变量
var num = 10;
console.log(num);
function test() {// 局部变量var num = 20;console.log(num);
}
function test2() {// 局部变量var num = 30;console.log(num);
}
test();
test2();
console.log(num);
// 执行结果
10
20
30
10
创建变量时如果不写 var, 则得到一个全局变量.
function test() {num = 100;
}
test();
console.log(num);
// 执行结果
100
var num = 1;
function test1() {var num = 10;function test2() {var num = 20;console.log(num);}
}
test2();
test1();
// 执行结果
20
执行 console.log(num) 的时候, 会现在 test2 的局部作用域中查找 num. 如果没找到, 则继续去 test1 中查找. 如果还没找到, 就去全局作用域查找
基本概念
在 JS 中, 字符串, 数值, 数组, 函数都是对象.
每个对象中包含若干的属性和方法.
JavaScript 的对象 和 Java 的对象概念上基本一致. 只是具体的语法表项形式差别较大.
使用 字面量 创建对象
var a = {}; // 创建了一个空的对象
var student = {name: '蔡徐坤',height: 175,weight: 170,sayHello: function() {console.log("hello");}
};
使用对象的方法和属性
// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的"
console.log(student.name);
// 2. 使用 [ ] 访问属性, 此时属性需要加上引号
console.log(student['height']);
// 3. 调用方法, 别忘记加上 ()
student.sayHello();
//增加一个属性hello
student.hello = 175;
使用 new Object 创建对象
var student = new Object(); // 和创建数组类似
student.name = "蔡徐坤";
student.height = 175;
student['weight'] = 170;
student.sayHello = function () {console.log("hello");
}
//使用
console.log(student.name);
console.log(student['weight']);
student.sayHello();
使用 构造函数 创建对象
基本语法
前面的创建对象方式只能创建一个对象. 而使用构造函数可以很方便 的创建 多个对象
如果想创建多个对象此时写起来就比较麻烦. 使用构造函数可以把相同的属性和方法的创建提取出来, 简化开发过程
function 构造函数名(形参) {this.属性 = 值;this.方法 = function...
}
var obj = new 构造函数名(实参);
注意:
例子
function Cat(name, type, sound) {this.name = name;this.type = type;this.miao = function () {console.log(sound); // 别忘了作用域的链式访问规则}
}
}
var mimi = new Cat('咪咪', '中华田园喵', '喵');
var xiaohei = new Cat('小黑', '波斯喵', '猫呜');
var ciqiu = new Cat('刺球', '金渐层', '咕噜噜');
console.log(mimi);
mimi.miao();
理解 new 关键字
new 的执行过程:
JavaScript 中的函数是 “一等公民”, 和普通的变量一样. 存储了函数的变量能够通过 ( ) 来进行调用执行
对象中的属性都可以被外界随意访问.
对象其实就是 “属性” + “方法” .
类相当于把一些具有共性的对象的属性和方法单独提取了出来, 相当于一个 “月饼模子”
在 JavaScript 中的 “构造函数” 也能起到类似的效果.
而且即使不是用构造函数, 也可以随时的通过 { } 的方式指定出一些对象
在 ES6 中也引入了 class 关键字, 就能按照类似于 Java 的方式创建类和对象了.
继承本质就是 “让两个对象建立关联”. 或者说是让一个对象能够重用另一个对象的属性/方法.
JavaScript 中使用 “原型” 机制实现类似的效果.
多态的本质在于 “程序猿不必关注具体的类型, 就能使用其中的某个方法”.
C++ / Java 等静态类型的语言对于类型的约束和校验比较严格. 因此通过 子类继承父类, 并重写父类的方法的方式 来实现多态的效果.
但是在 JavaScript 中本身就支持动态类型, 程序猿在使用对象的某个方法的时候本身也不需要对对象的类型做出明确区分. 因此并不需要在语法层面上支持多态.
前面学习的 JS 分成三个大的部分
WebAPI 就包含了 DOM + BOM.
这个是 W3C 组织规定的. (和制定 ECMAScript 标准的大佬们不是一伙人).
前面学的 JS 基础语法主要学的是 ECMAScript, 这让我们建立基本的编程思维. 相当于练武需要先扎马步.但是真正来写一个更加复杂的有交互式的页面, 还需要 WebAPI 的支持. 相当于各种招式.
DOM 全称为 Document Object Model.
W3C 标准给我们提供了一系列的函数, 让我们可以操作:
一个页面的结构是一个树形结构, 称为 DOM 树.
文档标题 我的链接我的标题
重要概念:
这些文档等概念在 JS 代码中就对应一个个的对象.所以才叫 "文档对象模型" .
也就是找到页面(文档)中对应的一个标签
前面的几种方式获取元素的时候都比较麻烦. 而使用 querySelector 能够完全复用前面学过的 CSS 选择器知识, 达到更快捷更精准的方式获取到元素对象
querySelector
var element = document.querySelector(selectors);
第一个元素
的 html元素 Element 对象. 例子
abc
def
querySelectorAll
使用 querySelectorAll 用法和上面类似
abc
def
JS 要构建动态页面, 就需要感知到用户的行为.
产生一个个事件
, 被 JS 获取到, 从而进行更复杂的交互操作
这个匿名函数相当于一个回调函数, 这个函数不需要程序猿主动来调用, 而是交给浏览器, 由浏览器自动在合适的时机(触发点击操作时) 进行调用.
我们操作元素和操作结点其最终的目的也就是改变我们的DOM树,从而让我们在浏览器能看到页面的变化
innerText
Element.innerText 属性表示一个节点及其后代的“渲染” 文本内容
// 读操作
var renderedText = HTMLElement.innerText;
// 写操作
HTMLElement.innerText = string;
hello worldhello world
innerHTML
Element.innerHTML 属性设置或获取HTML语法表示的元素的后代
.
// 读操作
var content = element.innerHTML;
// 写操作
element.innerHTML = htmlString;
hello worldhello world
可以看到 innerHTML 不光能获取到页面的 html 结构, 同时也能修改结构. 并且获取到的内容保留的空格和换行
关于innerHTML如何实现DOM结构的改变
可以通过 Element 对象的属性来直接修改, 就能影响到页面显示效果
实例
此时点击图片就可以切换图片显示状态. (需要提前把两个图片准备好)
表单(主要是指 input 标签)的以下属性都可以通过 DOM 来修改
代码示例: 切换按钮的文本.
如果是输入框, value 表示输入框的内容, 修改这个值会影响到界面显式; 在界面上修改这个值也会影响到代码中的属性
如果是按钮, value 表示按钮的内容. 可以通过这个来实现按钮中文本的替换
行内样式操作
CSS 中指定给元素的属性, 都可以通过 JS 来修改
element.style.[属性名] = [属性值];
element.style.cssText = [属性名+属性值];
“行内样式”, 通过 style 直接在标签上指定的样式. 优先级很高. 适用于改的样式少的情况
style 中的属性都是使用 驼峰命名 的方式和 CSS 属性对应的.
例如: font-size => fontSize, background-color => backgroundColor 等
这种方式修改只影响到特定样式, 其他内联样式的值不变.
哈哈
类名样式操作
element.className = [CSS 类名];
修改元素的 CSS 类名. 适用于要修改的样式很多的情况
分成两个步骤
此时发现, 虽然创建出新的 div 了, 但是 div 并没有显示在页面上. 这是因为新创建的节点并没有加入到DOM 树中
element.appendChild(aChild)
使用 removeChild 删除子节点
oldChild = element.removeChild(child);