基础学习:
前端最基础的就是 HTML , CSS 和 JavaScript 。
网页设计:HTML和CSS基础知识的学习
HTML是网页内容的载体。内容就是网页制作者放在页面上想要让用户浏览的信息,可以包含文字、图片、视频等。
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
CSS样式是表现。就像网页的外衣。比如,标题字体、颜色变化,或为标题加入背景图片、边框等。所有这些用来改变内容外观的东西称之为表现。
动态交互:JavaScript基础的学习
JavaScript是用来实现网页上的特效效果。如:鼠标滑过弹出下拉菜单。或鼠标滑过表格的背景颜色改变。还有焦点新闻(新闻图片)的轮换。可以这么理解,有动画的,有交互的一般都是用JavaScript来实现的。
var m = n - 0;
m; // returns NaN
typeof m; // returns “number”
- 使用 Boolean() 函数。比如:
Boolean(123); // returns true
Boolean(“abc”); // returns true
Boolean(null); // returns false
Boolean(undefined); // returns false
Boolean(NaN); // returns false
Boolean(0); // returns false
Boolean(“”); // returns false
Boolean(false); // returns false
Boolean(“false”); // returns true
Boolean(-1); // returns true
2.流程控制语句会把后面的值隐式转换为布尔类型。比如:
var message;
if (message) {
//会自动把 message 转换成 false,最后打印结果为:我很好
console.log(“你好啊”);
} else {
console.log(“我很好”);
}
=====================================================================================
生活中,条件与我们息息相关。举几个例子:如果这周放假,那么我就要出去玩;如果明天不下雨,我就和小花出去踢足球;如果我饿了,我要么吃饭,要么吃面,要么就忍着。同样的,在 JavaScript 中,我们也有条件语句,下面为大家讲解在 JavaScript 中如何使用条件语句。
if…else 语句
最基本的 if…else 语句。它的语法为:
if (条件) {
// 当条件为 true 时执行的语句
} else {
// 当条件为 false 时执行的语句
}
例子:
if (3 > 2) {
console.log(“我真帅”);
} else {
console.log(“不可能”);
}
上述例子在控制台中打印的语句为:我真帅。
- if…else 嵌套。它的语法是:
if(条件 1){
// 当条件 1 为 true 时执行的代码
}
else if(条件 2){
// 当条件 2 为 true 时执行的代码
}
else{
// 当条件 1 和 条件 2 都不为 true 时执行的代码
}
注:根据实际情况,还可以嵌套更多的 else if。
例子:
var d = new Date().getDay();
if (d == 0) {
console.log(“今天星期天”);
} else if (d == 1) {
console.log(“今天星期一”);
} else if (d == 2) {
console.log(“今天星期二”);
} else {
console.log(“好多啊,我不想写了”);
}
switch case 语句
从前面的例子中我们可以看出来,当条件很多的时候,一直嵌套 else if 语句,显然是有点不科学的,由此我们引出了 switch case 语句,先来看看它的语法:
switch(k){
case 1:
执行代码块 1 ;
break;
case 2:
执行代码块 2 ;
break;
default:
默认执行(k 值没有在 case 中找到匹配时);
}
通过 switch case 语句来改写上面的例子:
var d = new Date().getDay();
switch (d) {
case 0:
console.log(“今天星期天”);
break;
case 1:
console.log(“今天星期一”);
break;
case 2:
console.log(“今天星期二”);
break;
case 3:
console.log(“今天星期三”);
break;
case 4:
console.log(“今天星期四”);
break;
case 5:
console.log(“今天星期五”);
break;
default:
console.log(“今天星期六”);
break;
}
三元运算符
语法:
条件表达式?结果 1:结果 2
含义:问号前面的位置是判断的条件,判断结果为 boolean 型,为 true 时执行结果 1,为 false 时执行结果 2。
例子:
3 > 2 ? console.log(“3 比 2 大”) : console.log(“3 比 2 小”);
通过循环函数来帮助我们完成一些重复性的工作。
for 循环
for 循环是我们编码中经常会使用到的。先来看看它的语法结构:
for (初始化; 条件; 增量) {
循环代码;
}
举个打印 1 到 100 的例子:
for (var i = 1; i <= 100; i++) {
console.log(i);
}
使用 break 跳出循环
我们在前面的 switch case 结构中已经见过 break 语句了,当 switch 语句中符合输入表达式的情况满足时,break 语句立即退出 switch 语句并移动到之后的代码。上述的 for 循环例子,我们来加个条件,使其能打印一个能被 7 整除的整数。
for (var i = 1; i <= 100; i++) {
if (i % 7 == 0) {
console.log(i);
break;
}
}
使用 continue 跳过迭代
使用 continue 跳过迭代,不是完全跳出循环,而是跳过当前循环而执行下一个循环。比如我们使用 continue 可以实现打印 1 到 100 所有能被 7 整除的整数,而前面的例子中只能打印出:7。
for (var i = 1; i <= 100; i++) {
if (i % 7 == 0) {
console.log(i);
continue;
}
}
么写可能不好理解,大家或许会想到上面的例子不写 continue 最后打印的效果和写了是一样的啊,那 continue 是不是就没用了?其实 continue 主要是跳过当前循环去执行下一个循环也就是说,当前循环下的其他语句就不执行了。来看下面的例子:
for (var i = 1; i <= 7; i++) {
if (i % 7 == 0) {
console.log(i);
continue;
console.log(“*”);
}
}
可以把上面的代码运行一下,然后把 continue 删除,再运行一下,细细体会一下 continue 语句的作用。
while 语句 和 do while 语句
在 JavaScript 中不止有 for 循环,还有其他的循环语句。我们先来看看 while 循环的语法结构:
while (条件) {
// 需要执行的代码;
}
同样的,我们来写一个打印 1 到 100 之间整数的例子:
var i = 1;
while (i <= 100) {
console.log(i);
i++;
}
do while 循环的语法结构:
do {
// 需要执行的代码;
} while (条件);
例子:
var i = 1;
do {
console.log(i);
i++;
} while (i <= 100);
注:而这两者的区别是,do while 循环在检测条件之前就会执行,也就是说,即使条件为 false,do while 也会执行一次循环代码。而 while 循环只有在条件为真的时候才执行。 可以这样简单记忆:while 循环,先判断再执行;do while 循环先执行一次再判断。
函数是被设计为执行特定任务的代码块,可重复调用执行。我们平时写代码的时候,也会经常遇到重复使用的代码,那我们是重复的一行行敲,或者 cv(ctrl c + ctrl v)大法一顿操作呢?显然这样有点不科学,如果我们使用函数将这些重复的代码封装起来,那么在需要使用的时候,就可以直接调用了。
浏览器内置函数
其实在前面学习字符串和数组的时候,我们不知不觉已经使用了很多次函数。比如我们通过 join() 方法将数组转换为字符串,通过 split() 方法,将字符串转换为数组。这些都是浏览器已经封装好的内置函数,而我们可以直接调用。严格来说,内置浏览器函数并不是函数,它们是方法,但是没关系,我们前期学习阶段可以暂时不管这些,函数和方法在很大程度上是可互换的。
函数声明创建函数
语法为:
function functionName(parameters) {
// 执行的代码
}
例子:
function f(a, b) {
console.log(a + b);
} // 创建一个名为 f 的函数,它有两个形参 a,b
f(2, 3); // 调用函数 f,传入实参 2 和 3,最终运行结果为在控制台上打印出 5
函数表达式创建函数
JavaScript 函数可以通过一个表达式定义。函数表达式可以存储在变量中。
语法为:
var functionName = function (parameters) {
// 执行的代码
};
把函数声明创建函数的例子改写为用函数表达式创建函数:
var f = function (a, b) {
console.log(a + b);
};
f(2, 3);
函数声明和函数表达式的区别
- 函数声明
// 此处的代码执行没有问题,JavaScript 解析器首先会把当前作用域的函数声明提前到整个作用域的最前面。
f(2, 3);
function f(a, b) {
console.log(a + b);
}
- 函数表达式
// 报错:f is not a function
// 这是因为函数表达式,如同定义其它基本类型的变量一样,只在执行到某一句时也会对其进行解析
f(2, 3);
var f = function (a, b) {
console.log(a + b);
};
函数的参数
- 形参:function f(a, b){return a + b;} // a, b 是形参,占位用,函数定义时形参无值。
- 实参:当我们调用上面的函数时比如 f(2, 3);其中 2 和 3 就是实参,会传递给 a 和 b,最后函数中执行的语句就变成了:return 2 + 3;。
注:在 JavaScript 中,实参个数和形参个数可以不相等。
在 JavaScript 中没有重载
function f(a, b) {
return a + b;
}
function f(a, b, c) {
return a + b + c;
}
var result = f(5, 6);
result; // returns NaN
上述代码中三个参数的 f 把两个参数的 f 覆盖,调用的是三个参数的 f,最后执行结果为 NaN,而不是 11。
在 JavaScript 中函数的返回值
- 如果函数中没有 return 语句,那么函数默认的返回值是:undefined。
- 如果函数中有 return 语句,那么跟着 return 后面的值就是函数的返回值。
- 如果函数中有 return 语句,但是 return 后面没有任何值,那么函数的返回值也是:undefined。
- 函数在执行 return 语句后会停止并立即退出,也就是说 return 语句执行之后,剩下的代码都不会再执行了。
- 当函数外部需要使用函数内部的值的时候,我们不能直接给予,需要通过 return 返回。
比如:
var f = function (a, b) {
a + b;
};
console.log(f(2, 3)); // 结果为 undefined
var f = function (a, b) {
return a + b;
};
console.log(f(2, 3)); // 结果为 5
匿名函数
匿名函数就是没有命名的函数,一般用在绑定事件的时候。语法为:
function(){
// 执行的代码
}
例子:
var myButton = document.querySelector(“button”);
myButton.onclick = function () {
alert(“hello”);
};
注:将匿名函数分配为变量的值,也就是我们前面所讲的函数表达式创建函数。一般来说,创建功能,我们使用函数声明来创建函数。使用匿名函数来运行负载的代码以响应事件触发(如点击按钮),使用事件处理程序。
自调用函数
匿名函数不能通过直接调用来执行,因此可以通过匿名函数的自调用的方式来执行。比如:
(function () {
alert(“hello”);
})();
任务要求:自定义一个函数,提示用户输入一个正整数。如果用户输入的非正整数,提示用户输入错误,并返回输入界面让用户输入。直到用户输入一个正确的正整数后,在页面打印出一个由 * 组成的直角三角形。第一行打印一个 * ,第二行打印两个 * ,以此类推下去,最后一行的 * 个数为用户输入的正整数。比如我们输入 9,最后打效果如下:
参考源码:
=========================================================================
在 JavaScript 中所有事物都是对象:字符串,数组,日期等等。我们甚至可以自己创建对象,将相关的函数和变量封装打包成便捷的数据容器。另外值得注意的是 JavaScript 是一门基于对象的语言。感兴趣的话可以自行百度面向对象和基于对象的区别,这里不影响我们对于 JavaScript 中对象的讲解。
在 JavaScript 中对象是拥有属性和方法的数据。
属性和方法
属性是与对象相关的值,也可以理解为特征。方法是能够在对象上执行的动作,也可以理解为行为。
举个例子:一辆汽车就是现实生活中的对象,它的名字,它的颜色,它的价格等特征就是汽车对象的属性。它能够启动,驾驶,加速,刹车等行为就是汽车对象的方法。
JSON(JavaScript Object Notation,JavaScript 对象表示法)是一种由道格拉斯·克罗克福特构想和设计、轻量级的数据交换语言,该语言以易于让人阅读的文字为基础,用来传输由属性值或者序列性的值组成的数据对象。尽管 JSON 是 JavaScript 的一个子集,但 JSON 是独立于语言的文本格式,并且采用了类似于 C 语言家族的一些习惯。
JSON 数据格式与语言无关,脱胎于 JavaScript,但当前很多编程语言都支持 JSON 格式数据的生成和解析。JSON 的官方 MIME 类型是 application/json,文件扩展名是 .json。
注:定义来自维基百科。
下面给出两个简单的 json 示例:
{
“name”: “zhangsan”,
“age”: 18,
“gender”: “male”
}
{
“students”: [
{ “firstName”: “san”, “lastName”: “zhang” },
{ “firstName”: “si”, “lastName”: “li” },
{ “firstName”: “wu”, “lastName”: “wang” }
]
}
特别需要注意的是:
- JSON 是一种纯数据格式,它只包含属性,没有方法。
- JSON 的属性必须通过双引号引起来。
- JSON 要求两头有 {} 来使其合法。
- 可以把 JavaScript 对象原原本本的写入 JSON 数据,比如:字符串,数字,数组,布尔还有其它的字面值对象。
前面在讲数组的方法和字符串的操作的时候,已经讲解了一部分内置对象的内容。这里我再系统的讲解一下一些常用的内置对象。
Array 对象
- Array 对象的常用属性:length,获取数组的长度。
- Array 对象的常用方法:
- concat() 方法用于连接两个或多个数组,并返回结果。
语法为:
arrayObject.concat(arrayX, arrayX, …, arrayX);
例子:
var a = [1, 2, 3];
var b = [4, 5, 6];
var c = [“one”, “two”, “three”];
console.log(a.concat(b, c)); // 打印结果为:[1, 2, 3, 4, 5, 6, “one”, “two”, “three”]
- join() 方法,将数组转换成字符串。
- pop() 方法,删除并返回数组的最后一个元素。
- push() 方法,向数组的末尾添加一个或更多元素,并返回新的长度。
- reverse() 方法,颠倒数组的顺序。
比如:
var a = [1, 2, 3, 4];
a.reverse();
console.log(a); // a 数组变成:[4, 3, 2, 1]。
- shift() 方法,删除并返回数组的第一个元素。
- unshift() 方法,向数组的开头添加一个或更多元素,并返回新的长度。
- slice() 方法,从某个已有的数组返回选定的元素。
语法为:
arrayObject.slice(start, end);
// strat 值是必需的,规定从何处开始选取
// end 值可选,规定从何处结束选取,如果没有设置,默认为从 start 开始选取到数组后面的所有元素
在控制台中输入以下代码:
var a = [1, 2, 3, 4, 5, 6];
a.slice(2, 5); // 结果为[3, 4, 5],另外需要注意的是该方法不会修改数组,只是返回一个子数组,a 数组还是 [1, 2, 3, 4, 5, 6]
- splice() 方法,删除或替换当前数组的某些项目。
语法为:
arrayObject.splice(start, deleteCount, options);
// start 值是必需的,规定删除或替换项目的位置
// deleteCount 值是必需的,规定要删除的项目数量,如果设置为 0,则不会删除项目
// options 值是可选的,规定要替换的新项目
// 和 slice() 方法不同的是 splice() 方法会修改数组
在控制台中输入以下代码:
var a = [1, 2, 3, 4, 5, 6];
a.splice(2, 2, “abc”);
a; // 最终 a 数组变成了[1, 2, “abc”, 5, 6]
- sort() 方法,将数组进行排序。
语法为:
arrayObject.sort(sortby);
// sortby 是可选的,规定排序顺序,必需是函数。如果没有参数的话,将会按照字母顺序进行排序,更准确的说是按照字符编码(可自行百度了解)的顺序进行排序。如果想按照其他标准进行排序,则需要提供比较函数
例子:
运行结果为:
- toString() 方法,把数组转换为字符串,并返回结果。
String 对象
1.String 对象的常用属性:length,获取字符串的长度。
2. String 对象的常用方法:
- charAt() 方法,获取指定位置处字符。
语法为:
stringObject.charAt(index);
// 字符串中第一个字符的下标是 0。如果参数 index 不在 0 与 string.length 之间,该方法将返回一个空字符串
例子:
var str = “Hello world!”;
document.write(str.charAt(2));
// 以上代码输出为 l
- charCodeAt() 方法,获取指定位置处字符的 Unicode 编码。
语法为:
stringObject.charCodeAt(index);
// 字符串中第一个字符的下标是 0。如果 index 是负数,或大于等于字符串的长度,则 charCodeAt() 返回 NaN
例子:
var str = “Hello world!”;
document.write(str.charCodeAt(2));
// 以上代码输出为 l08
- oncat() 方法,连接字符串,等效于 “+”,“+” 更常用。与数组中的 concat() 方法相似。
- slice() 方法,提取字符串的片断,并在新的字符串中返回被提取的部分(字符串章节有详细介绍,这里不过多的赘述,下面的类似情况同样处理)。
- indexOf() 方法,检索字符串。
- toString() 方法,返回字符串。
- toLowerCase() 方法,把字符串转换为小写。
- toUpperCase() 方法,把字符串转换为大写。
- replace() 方法,替换字符串中的某部分。
- split() 方法,把字符串分割为字符串数组。
Date 对象
Date 对象方法:
- Date():返回当日的日期和时间(输出的是中国标准时间)。
- getDate():从 Date 对象返回一个月中的某一天 (1 ~ 31)。
- getDay():从 Date 对象返回一周中的某一天 (0 ~ 6)。
- getMonth():从 Date 对象返回月份 (0 ~ 11)。
- getFullYear():从 Date 对象以四位数字返回年份。
- getHours():返回 Date 对象的小时 (0 ~ 23)。
- getMinutes():返回 Date 对象的分钟 (0 ~ 59)。
- getSeconds():返回 Date 对象的秒数 (0 ~ 59)。
- getMilliseconds():返回 Date 对象的毫秒(0 ~ 999)。
Math 对象
Math 对象的常用属性:
- E :返回常数 e (2.718281828…)。
- LN2 :返回 2 的自然对数 (ln 2)。
- LN10 :返回 10 的自然对数 (ln 10)。
- LOG2E :返回以 2 为底的 e 的对数 (log2e)。
- LOG10E :返回以 10 为底的 e 的对数 (log10e)。
- PI :返回 π(3.1415926535…)。
- SQRT1_2 :返回 1/2 的平方根。
- SQRT2 :返回 2 的平方根。
Math 对象的常用方法:
- abs(x) :返回 x 的绝对值。
- round(x) :返回 x 四舍五入后的值。
- sqrt(x) :返回 x 的平方根。
- ceil(x) :返回大于等于 x 的最小整数。
- floor(x) :返回小于等于 x 的最大整数。
- sin(x) :返回 x 的正弦。
- cos(x) :返回 x 的余弦。
- tan(x) :返回 x 的正切。
- acos(x) :返回 x 的反余弦值(余弦值等于 x 的角度),用弧度表示。
- asin(x) :返回 x 的反正弦值。
- atan(x) :返回 x 的反正切值。
- exp(x) :返回 e 的 x 次幂 (e^x)。
- pow(n, m) :返回 n 的 m 次幂 (nm)。
- log(x) :返回 x 的自然对数 (ln x)。
- max(a, b) :返回 a, b 中较大的数。
- min(a, b) :返回 a, b 中较小的数。
- random() :返回大于 0 小于 1 的一个随机数。
创建对象的方式有很多,下面讲解几种常用的方式。
通过对象字面量来创建
var student = {
name: “zhangsan”,
age: 18,
gender: “male”,
sayHi: function () {
console.log("hi,my name is " + this.name);
},
};
把上面的代码复制到控制台中,然后尝试依次输入下面的代码看看效果:
student.name;
student.age;
student.gender; // 调用对象的属性
student.sayHi(); // 调用对象的方法
通过上面的例子会发现对象的属性和方法通过 “.” 来访问。
通过 new Object() 创建对象
var student = new Object();
(student.name = “zhangsan”),
(student.age = 18),
(student.gender = “male”),
(student.sayHi = function () {
console.log("hi,my name is " + this.name);
});
通过工厂函数创建对象
function createStudent(name, age, gender) {
var student = new Object();
student.name = name;
student.age = age;
student.gender = gender;
student.sayHi = function () {
console.log("hi,my name is " + this.name);
};
return student;
}
var s1 = createStudent(“zhangsan”, 18, “male”);
自定义构造函数
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = function () {
console.log("hi,my name is " + this.name);
};
}
var s1 = new Student(“zhangsan”, 18, “male”);
new 关键字
构造函数,是一种特殊的函数。主要用来在创建对象时初始化对象,即为对象成员变量赋初始值,总与 new 运算符一起使用在创建对象的语句中。
这里有需要特别注意的几点:
- 构造函数用于创建一类对象,首字母要大写。
- 内部使用 this 关键字给对象添加成员。
- 使用 new 关键字调用对象构造函数。
this 详解
在 JavaScript 中,我们经常会使用到 this 关键字,那么 this 到底指向什么呢?这里有一个口诀:谁调用 this,它就是谁。
- 函数在定义的时候 this 是不确定的,只有在调用的时候才可以确定。
- 一般函数直接执行,内部 this 指向全局 window。
比如:
function test() {
console.log(this);
}
test(); // window.test();
- 函数作为一个对象的方法,被该对象所调用,那么 this 指向的是该对象。
- 构造函数中的 this,始终是 new 的当前对象。
遍历对象的属性
通过 for…in 语句用于遍历数组或者对象的属性,对数组或者对象的属性进行循环操作。比如:
注:key 是一个变量,这个变量中存储的是该对象的所有的属性的名字。
删除对象的属性
使用 delete 删除对象的属性。比如在控制台中输入以下代码:
var student = {
name: “zhangsan”,
age: 18,
gender: “male”,
};
student.name; // zhangsan
delete student.name;
student.name; // undefined
============================================================================
API(Application Programming Interface,应用程序编程接口):“计算机操作系统”(Operating system)或"程序库"提供给应用程序调用使用的代码。其主要目的是让应用程序开发人员得以调用一组例程功能,而无须考虑其底层的源代码为何、或理解其内部工作机制的细节。API 本身是抽象的,它仅定义了一个接口,而不涉及应用程序在实际实现过程中的具体操作。
注:定义来自维基百科。
Web API
Web API 是浏览器提供的一套操作浏览器功能和页面元素的 API(BOM 和 DOM)。
浏览器对象模型(Browser Object Model (BOM))指的是由 Web 浏览器暴露的所有对象组成的表示模型。BOM 与 DOM(Document Object Model,文档对象模型)不同,其既没有标准的实现,也没有严格的定义,所以浏览器厂商可以自由地实现 BOM。
作为显示文档的窗口,浏览器程序将其视为对象的分层集合。当浏览器分析文档时,它将创建一个对象的集合,以定义文档,并详细说明它应如何显示。浏览器创建的对象称为文档对象,它是浏览器使用的更大的对象集合的一部分。此浏览器对象集合统称为浏览器对象模型或 BOM。
BOM 层次结构的顶层是窗口对象,它包含有关显示文档的窗口的信息。某些窗口对象本身就是描述文档和相关信息的对象。
注:定义来自维基百科。
window 是浏览器的顶级对象,当调用 window 下的属性和方法时,可以省略 window。
对话框
- alert():显示带有一段消息和一个确认按钮的警告框。
- prompt():显示可提示用户输入的对话框。
- confirm():显示带有一段消息以及确认按钮和取消按钮的对话框。
页面加载事件
- onload
window.onload = function () {
// 当页面加载完成执行
// 当页面完全加载所有内容(包括图像、脚本文件、CSS 文件等)执行
};
- onunload
window.onunload = function () {
// 当用户退出页面时执行
};
浏览器尺寸
var width = window.innerWidth;
document.documentElement.clientWidth;
document.body.clientWidth;
var height = window.innerHeight;
document.documentElement.clientHeight;
document.body.clientHeight;
上述代码可以获取所有浏览器的宽高(不包括工具栏/滚动条)。
定时器
- setTimeout() 方法在指定的毫秒数到达之后执行指定的函数,只执行一次。clearTimeout() 方法取消由 setTimeout() 方法设置的 timeout。
// 创建一个定时器,2000毫秒后执行,返回定时器的标示
var timerId = setTimeout(function () {
console.log(“Hello”);
}, 2000);
// 取消定时器的执行
clearTimeout(timerId);
- setInterval() 方法设置定时调用的函数也就是可以按照给定的时间(单位毫秒)周期调用函数,clearInterval() 方法取消由 setInterval() 方法设置的 timeout。
// 创建一个定时器,每隔 2 秒调用一次
var timerId = setInterval(function () {
var date = new Date();
console.log(date.toLocaleTimeString());
}, 2000);
// 取消定时器的执行
clearInterval(timerId);
注:BOM 的操作方法还有很多,但是一般情况下我们常用的就是上面所介绍的。有兴趣的可以自行百度了解 BOM 的更多操作方法和介绍。
文档对象模型(Document Object Model,简称 DOM),是 W3C 组织推荐的处理可扩展标志语言的标准编程接口。DOM 定义了访问 HTML 和 XML 文档的标准。我们这里主要学习 HTML DOM。DOM 可以把 HTML 看做是文档树,通过 DOM 提供的 API 可以对树上的节点进行操作。下面来看一下 W3C 上的 DOM 树:
DOM 能够操作 HTML 的内容。
改变 HTML 输出流
在 JavaScript 中,使用 document.write() 可用于直接向 HTML 输出流写内容。比如:
document.write(“新设置的内容
标签也可以生成
”);在控制台中复制上述代码运行后:
改变 HTML 内容
使用 innerHTML 属性改变 HTML 内容。比如修改 p 标签中的内容:
Hello World!
改变 HTML 属性
语法:
document.getElementById(id).attribute = new value();
DOM 能够改变 HTML 元素的样式。语法为:
document.getElementById(id).style.property = new style();
例子:
Hello
注:在上述例子中,p 标签中Hello的颜色本来为红色,但是通过 DOM 方法,最后将其改变成了绿色。运行上述代码,最终的效果是显示一个颜色为绿色的Hello文本。
根据 W3C 的 HTML DOM 标准,HTML 文档中的所有内容都是节点:整个文档就是一个文档节点,而每一个 HTML 标签都是一个元素节点。HTML 标签中的文本则是文本节点,HTML 标签的属性是属性节点,一切都是节点。
获取节点
要操作节点,首先我们要找到节点。主要有以下三种办法:
- 通过 ID 找到 HTML 元素:使用方法 getElementById() 通过元素的 ID 而选取元素,比如:
document.getElementById(“demo”); // 假定已经有一个 ID 名为 demo 的标签,可以这样来获取它
- 通过标签名找到 HTML 元素:使用方法 getElementsByTagName() 来选取元素,如果有多个同类型标签,那么我们可以通过下标来确认,比如:
- 通过类名来找到 HTML 元素:使用方法 getElementsByClassName() 通过元素的类名来选取元素。比如:
document.getElementsByClassName(“name”); // 返回包含 class = “name” 的所有元素的一个列表。
DOM 节点之间的关系
DOM 的节点并不是孤立的,我们从 DOM 树中也可以看出,节点与节点之间存在着相对的关系,就如同一个家族一样,有父辈,有兄弟,有儿子等等。下面我们来看一下都有哪些节点:
| 父节点 | 兄弟节点 | 子节点 | 所有子节点 |
| — | — | — | — |
| parentNode | nextSibling | firstChild | childNodes |
| | nextElementSibling | firstElementChild | children |
| | previousSibling | lastChild | |
| | previousElementSibling | lastElementChild | |
例子:
我是h1标签
我是p标签
上面的例子中:
- 节点没有父节点,它是根节点。
- 和 的父节点是 节点。
- 文本节点 我是 p 标签 的父节点是
节点。
- 节点有两个子节点: 和 。
节点和
节点是兄弟节点,同时也是 的子节点。
需要注意以下几点:
- childNodes:它是标准属性,它返回指定元素的子元素集合,包括 HTML 节点,所有属性,文本节点。
- children:非标准属性,它返回指定元素的子元素集合。但它只返回 HTML 节点,甚至不返回文本节点。
- nextSibling 和 previousSibling 获取的是节点,获取元素对应的属性是 nextElementSibling 和 previousElementSibling。
- nextElementSibling 和 previousElementSibling 有兼容性问题,IE9 以后才支持。
DOM 节点的操作
- 创建节点
- 创建元素节点:使用 createElement() 方法。比如:
var par = document.createElement(“p”);
-
创建属性节点:使用 createAttribute() 方法。
-
创建文本节点:使用 createTextNode() 方法。
- 插入子节点
-
appendChild () 方法向节点添加最后一个子节点。
-
insertBefore (插入的新的子节点,指定的子节点) 方法在指定的子节点前面插入新的子节点。如果第二个参数没写或者为 null,则默认插入到后面。
- 删除节点:使用 removeChild() 方法。写法为:
父节点.removeChild(子节点);
node.parentNode.removeChild(node); // 如果不知道父节点是什么,可以这样写
- 替换子节点:使用 replaceChild() 方法。语法为:
node.replaceChild(newnode, oldnode);
- 设置节点的属性:
-
获取:getAttribute(name)
-
设置:setAttribute(name, value)
-
删除:removeAttribute(name)
事件的定义
在什么时候执行什么事。
事件三要素
事件由:事件源 + 事件类型 + 事件处理程序组成。
- 事件源:触发事件的元素。
- 事件类型:事件的触发方式(比如鼠标点击或键盘点击)。
- 事件处理程序:事件触发后要执行的代码(函数形式,匿名函数)。
常用的事件
例子 1 :鼠标单击事件:
请点击该文本
例子 2 :鼠标双击事件:
请点击该文本
例子 3 :鼠标移除悬停:
οnmοuseοver=“mOver(this)”
οnmοuseοut=“mOut(this)”
style=“background-color:deepskyblue;width:200px;height:100px;”
把鼠标移到上面
参考源码:
首页
HTML
CSS
JavaScript
关于
帮助
=================================================================================
值类型
值类型又叫基本数据类型,在 JavaScript 中值类型有以下五种:
- 数值类型
- 布尔类型
- undefined
- null
- 字符串
值类型存储在栈(stack)中,它们的值直接存储在变量访问的位置。比如:
var num = 18;
var flag = true;
var un = undefined;
var nu = null;
var str = “zhangsan”;
上面定义的这些值类型的数据在内存中的存储如下图所示:
引用类型
引用类型又叫复合数据类型,在 JavaScript 中引用类型有以下三种:
- 对象
- 数组
- 函数
引用类型存储在堆中,也就是说存储在变量处的值是一个指针,指向存储对象的内存处。比如:
var arr = [1, 2, 3];
var p = { name: “张三”, age: 18 };
上面定义的这些引用类型的数据在内存中的存储如下图所示:
值类型的特征
- 值类型的值是不可变的,不可变是指值类型指向的空间不可变。比如:
var a = 2;
a = a + 2;
console.log(a); // 打印结果为 4。
在上述例子中,a 变量指向的值变了,但是 2 的内存没有变。
- 按值传递的变量之间互不影响。比如:
var a = 1;
var b = a;
a = a + 2;
console.log(a, b); // 打印结果为 3, 1
- 值类型赋值,直接将值赋值一份。比如:
var num1 = 10;
var num2 = num1;
上述代码在内存中的体现为:
- 当参数为值类型的时候,函数内和函数外的两个变量完全不同,仅仅只是存的值一样而已,修改时互不影响。比如:
function foo(num) {
num = num + 1;
}
var a = 1;
foo(a);
console.log(a); // 打印结果为 1
引用类型的特征
- 引用类型赋值,是将地址复制一份。比如:
var p = { name: “zhangsan”, age: 18 };
var p1 = p;
上述代码在内存中的体现为:
var p = { name: “张三”, age: 18 };
var p1 = p;
console.log(p.name); // 打印结果为张三
console.log(p1.name); // 打印结果为张三
p.name = “李四”;
console.log(p.name); // 打印结果为李四
console.log(p1.name); // 打印结果为李四
- 当参数为引用类型的时候,函数内和函数外的两个变量不同,但是共同指向同一个对象,在函数内修改对象数据时会影响外部。比如:
function foo(o) {
o.age = o.age + 1;
}
var p = { name: “zhangsan”, age: 18 };
foo§;
console.log(p.age); // 打印结果为 19。
注:可以这样理解。引用类型中的地址是一把钥匙,钥匙指向的是宝藏,复制一把钥匙后,两把钥匙能打开的是同一个宝藏。
在编写 JavaScript 代码时,如果遇见错误,首先在浏览器中运行我们的代码,然后 F12,查看错误信息。比如运行以下代码:
首先查看控制台信息,在控制台中会有报错提示,一般看这个就能知道问题是什么了。
在 Sources 中能够清楚的看到哪一行的代码出问题了,会有很明显地提醒。
如果我们想知道变量的值,在调试的时候,可以加一句 console.log(变量) 语句来打印出来,然后在控制台中看。console.log() 语句也是我们编程中经常需要使用的,因为有时候,我们也不能直观的一下就知道传递进来的值到底是什么,可能需要看半天的逻辑然后计算半天。直接打印出来的方式也有利于帮助我们判断,不过一般情况下大家记得调试完,要把这行语句注释掉或者删掉。
设置断点,逐步执行
首先运行上述代码,点击 F12 进行调试界面,点击 Sources,设置断点的方法很简单,直接左键点击代码旁边的数字行数。如下所示:
将变量添加到 Watch 窗口,实时查看它的值的变化,如下所示:
准备工作做好之后我们还需要点击一下刷新.然后就可以通过点击运行按钮,逐行运行我们设置断点时的代码,并在 Watch 中查看变量值的变化,如下所示:
在我们实际编程过程中,经常会遇到各种各样的错误,有可能是语法错误,也可能是拼写错误,也可能是浏览器的兼容性问题或者其它莫名其妙的问题。当出现错误时,JavaScript 引擎通常会停止,并生成一个错误信息。那我们应该怎么来调试我们的代码呢?
异常捕获
我们使用 try-catch 语句开捕获异常,语法为:
try {
// 这里写可能出现异常的代码
} catch (err) {
// 在这里写,出现异常后的处理代码
}
例子:
需要注意以下几点:
- 语句 try 和 catch 是成对出现的。
- 如果在 try 中出现了错误,try 里面出现错误的语句后面的代码都不再执行,直接跳转到 catch 中,catch 处理错误信息,然后再执行后面的代码。
- 如果 try 中没有出现错误,则不会执行 catch 中的代码,执行完 try 中的代码后直接执行后面的代码。
- 通过 try-catch 语句进行异常捕获之后,代码将会继续执行,而不会中断。
throw 语句
通过 throw 语句,我们可以创建自定义错误。throw 语句常常和 try catch 语句一起使用。
例子:
请输入 0 到 100 之间的数字:
测试输入值
===========================================================================
通过一个例子,来感受一下什么叫面向对象编程。比如我们设置页面中的 div 标签 和 p 标签的背景色为 color。如果按照我们前面所需我们可能会这样写:
你好吗?我很好
测试一下嘛好的啊
是不是觉得有点麻烦?好像有重复的?有的人可能会想到用函数来封装一下相同的代码:
你好吗?我很好
测试一下嘛好的啊
我们再来看看使用面向对象的方式:
你好吗?我很好
测试一下嘛好的啊
首先,我们来复习一下创建对象的方式。
- 通过对象字面量来创建。
var student = {
name: “zhangsan”,
age: 18,
gender: “male”,
sayHi: function () {
console.log("hi,my name is " + this.name);
},
};
- 通过 new Object() 创建对象。
var student = new Object();
(student.name = “zhangsan”),
(student.age = 18),
(student.gender = “male”),
(student.sayHi = function () {
console.log("hi,my name is " + this.name);
});
上面两种都是简单的创建对象的方式,但是如果有两个 student 实例对象呢?cv(Ctrl C + Ctrl V) 大法?分别命名一下 student1 和 student2?那如果是一个班的学生,n 个学生呢?显然如果这样做的话代码冗余率太高,是不可取的。我们也学过函数,所以简单方式的改进是:工厂函数。
- 通过工厂函数来创建对象。
function createStudent(name, age, gender) {
var student = new Object();
student.name = name;
student.age = age;
student.gender = gender;
student.sayHi = function () {
console.log("hi,my name is " + this.name);
};
return student;
}
var s1 = createStudent(“zhangsan”, 18, “male”);
var s2 = createStudent(“lisi”, 19, “male”);
这样封装代码确实解决了代码冗余的问题,但是每次调用函数 createStudent() 都会创建新函数 sayHi(),也就是说每个对象都有自己的 sayHi() 版本,而事实上,每个对象都共享一个函数。为了解决这个问题,我们引入面向对象编程里的一个重要概念:构造函数。
- 通过构造函数来创建对象。
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = function () {
console.log("hi,my name is " + this.name);
};
}
var s1 = new Student(“zhangsan”, 18, “male”);
来看看构造函数与工厂函数的区别:
- 首先在构造函数内没有创建对象,而是使用 this 关键字,将属性和方法赋给了 this 对象。
- 构造函数内没有 return 语句,this 属性默认下是构造函数的返回值。
- 函数名使用的是大写的 Student。
- 用 new 运算符和类名 Student 创建对象。
构造函数虽然科学,但仍然存在一些问题。
我们使用前面的构造函数例子来讲解(修改了 sayHi() 方法):
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = function () {
console.log(“hi”);
};
}
首先我们创建两个实例化对象:
var s1 = new Student(“zhangsan”, 18, “male”);
s1.sayHi(); // 打印 hi
var s2 = new Student(“lisi”, 18, “male”);
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayhi); // 结果为 false
效果:
由于每个对象都是由 new Student 创建出来的,因此每创建一个对象,函数 sayHi() 都会被重新创建一次,这个时候,每个对象都拥有一个独立的,但是功能完全相同的方法,这样势必会造成内存浪费。有的人可能会想,既然是一样的那我们就单独把它提出来,写一个函数,每次调用不就可以了吗?比如:
function sayHi() {
console.log(“hi”);
}
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = sayHi;
}
var s1 = new Student(“zhangsan”, 18, “male”);
s1.sayHi(); // 打印 hi
var s2 = new Student(“lisi”, 18, “male”);
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayHi); // 结果为 true
但是这样做会导致全局变量增多,可能会引起命名冲突,代码结果混乱,维护困难。通过使用原型可以很好的解决这个问题。
原型:prototype
在 JavaScript 中,每一个函数都有一个 prototype 属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。我们来看看前面例子原型的写法:
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
Student.prototype.sayHi = function () {
console.log(“hi”);
};
var s1 = new Student(“zhangsan”, 18, “male”);
s1.sayHi(); // 打印 hi
var s2 = new Student(“lisi”, 18, “male”);
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayHi); // 结果为 true
我们之前提到过:每一个函数都有一个 prototype 属性,指向另一个对象。让我们用代码验证一下,在编辑器中输入以下代码:
上述代码在浏览器中打印结果为 Object,验证了我们所说的 prototype 属性,指向另一个对象。
构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数。在控制台中运行下面的代码:
function F() {}
console.log(F.prototype.constructor === F); // 结果为 ture
通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 __ proto__。__ proto__属性最早是火狐浏览器引入的,用以通过实例对象来访问原型,这个属性在早期是非标准的属性。在控制台中运行下面的代码:
function F() {}
var a = new F();
console.log(a.proto === F.prototype); // 结果为 true
实例对象可以直接访问原型对象成员,所有实例都直接或间接继承了原型对象的成员。
总结:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针 constructor,而实例都包含一个指向原型对象的内部指针__proto__。
我们说过所有的对象都有原型,而原型也是对象,也就是说原型也有原型,那么如此下去,也就组成了我们的原型链。
属性搜索原则
最后
文章到这里就结束了,如果觉得对你有帮助可以点个赞哦
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
(“zhangsan”, 18, “male”);
var s2 = createStudent(“lisi”, 19, “male”);
这样封装代码确实解决了代码冗余的问题,但是每次调用函数 createStudent() 都会创建新函数 sayHi(),也就是说每个对象都有自己的 sayHi() 版本,而事实上,每个对象都共享一个函数。为了解决这个问题,我们引入面向对象编程里的一个重要概念:构造函数。
- 通过构造函数来创建对象。
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = function () {
console.log("hi,my name is " + this.name);
};
}
var s1 = new Student(“zhangsan”, 18, “male”);
来看看构造函数与工厂函数的区别:
- 首先在构造函数内没有创建对象,而是使用 this 关键字,将属性和方法赋给了 this 对象。
- 构造函数内没有 return 语句,this 属性默认下是构造函数的返回值。
- 函数名使用的是大写的 Student。
- 用 new 运算符和类名 Student 创建对象。
构造函数虽然科学,但仍然存在一些问题。
我们使用前面的构造函数例子来讲解(修改了 sayHi() 方法):
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = function () {
console.log(“hi”);
};
}
首先我们创建两个实例化对象:
var s1 = new Student(“zhangsan”, 18, “male”);
s1.sayHi(); // 打印 hi
var s2 = new Student(“lisi”, 18, “male”);
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayhi); // 结果为 false
效果:
由于每个对象都是由 new Student 创建出来的,因此每创建一个对象,函数 sayHi() 都会被重新创建一次,这个时候,每个对象都拥有一个独立的,但是功能完全相同的方法,这样势必会造成内存浪费。有的人可能会想,既然是一样的那我们就单独把它提出来,写一个函数,每次调用不就可以了吗?比如:
function sayHi() {
console.log(“hi”);
}
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
this.sayHi = sayHi;
}
var s1 = new Student(“zhangsan”, 18, “male”);
s1.sayHi(); // 打印 hi
var s2 = new Student(“lisi”, 18, “male”);
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayHi); // 结果为 true
但是这样做会导致全局变量增多,可能会引起命名冲突,代码结果混乱,维护困难。通过使用原型可以很好的解决这个问题。
原型:prototype
在 JavaScript 中,每一个函数都有一个 prototype 属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。我们来看看前面例子原型的写法:
function Student(name, age, gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
Student.prototype.sayHi = function () {
console.log(“hi”);
};
var s1 = new Student(“zhangsan”, 18, “male”);
s1.sayHi(); // 打印 hi
var s2 = new Student(“lisi”, 18, “male”);
s2.sayHi(); // 打印 hi
console.log(s1.sayHi == s2.sayHi); // 结果为 true
我们之前提到过:每一个函数都有一个 prototype 属性,指向另一个对象。让我们用代码验证一下,在编辑器中输入以下代码:
上述代码在浏览器中打印结果为 Object,验证了我们所说的 prototype 属性,指向另一个对象。
构造函数的 prototype 对象默认都有一个 constructor 属性,指向 prototype 对象所在函数。在控制台中运行下面的代码:
function F() {}
console.log(F.prototype.constructor === F); // 结果为 ture
通过构造函数得到的实例对象内部会包含一个指向构造函数的 prototype 对象的指针 __ proto__。__ proto__属性最早是火狐浏览器引入的,用以通过实例对象来访问原型,这个属性在早期是非标准的属性。在控制台中运行下面的代码:
function F() {}
var a = new F();
console.log(a.proto === F.prototype); // 结果为 true
实例对象可以直接访问原型对象成员,所有实例都直接或间接继承了原型对象的成员。
总结:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针 constructor,而实例都包含一个指向原型对象的内部指针__proto__。
我们说过所有的对象都有原型,而原型也是对象,也就是说原型也有原型,那么如此下去,也就组成了我们的原型链。
属性搜索原则
最后
文章到这里就结束了,如果觉得对你有帮助可以点个赞哦
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
[外链图片转存中…(img-jqfAz73Y-1715908446575)]