JavaScript 是一种轻量级的、弱类型的脚本语言。
一. 基本数据类型
1. Number(数值)
- Number():将值转换成数字
Number(false) = 0;
Number(null) = 0;
Number(undefined) = NaN; // Number(string) 用法类似 parseInt(string)
- parseInt():字符串转整数
parseInt('12.55') = 12;
parseInt('hello') = NaN; // NaN(Not-a-Number),表示无效的数值。NaN用于表示数值运算中的错误或未定义的结果。
paseInt('HaHa123') = 123;
- 模板字符串:反引号( ` )和
${}
const name = 'John';
const str = `my name is ${name}`;
2. String(字符串)
- 使用
+
拼接字符串:"1" + "2" = "12";
- toString():除 null 和 undefined 之外的其他类型转字符串
const num = 123;
num.toString(); // '123'
- String():将值转换成字符串
String(null) = "null";
String(undefined) = "undefined";
-
includes():字符串中是否存在指定的子字符串
'Hello world'.includes('ll') = true
-
字符串截取
- slice(start, end):[start, end),end可省略(截取到末尾),start 和 end 可以为负数,start < end
- substring(start, end):[start, end),start和end为非负整数,end可省略
- substr(start, len):start 可为负数,len 表示截取长度
const str = ‘Hello, world!’; str.slice(-3, -1) = 'ld'; str.substring(1, 3) = 'el'; str.substr(1, 3) = 'ell';
-
boolean(布尔值)
-
undefined(未定义):表示变量已声明但没有赋值时默认为undefined,或者访问对象或数组中不存在的元素
-
null(空值):明确赋值为null,表示变量或属性是空或不存在
-
Symbol:ES6 引入的新的基础数据类型,表示独一无二的值。
二. 引用数据类型
1. Array(数组)
-
添加
- push():数组末尾添加一个或多个元素,改变原数组,返回新数组长度
[1, 2, 3].push(4, 5) = 5;
- unshift():数组头部增加一个或多个元素,修改原数组,返回新数组长度
[1, 2, 3].unshift(0) => [0, 1, 2, 3];
- push():数组末尾添加一个或多个元素,改变原数组,返回新数组长度
-
删除
- pop():删除并返回数组最后一个元素
- shift() :删除并返回数组第一个元素
-
合并
- concat():合并两个数组
[1, 2, 3].concat([4, 5]) = [1, 2, 3, 4, 5];
- … 扩展运算符:
[1, 2, 3, ...[4, 5]] = [1, 2, 3, 4, 5];
- concat():合并两个数组
-
排序
- sort():默认按字母升序排列,改变原数组
var points = [40,100,1,5,25,10]; points.sort(); // [1, 10, 100, 25, 40, 5] points.sort((a, b) => b-a); // 数字倒序排列
-
查询
- array.indexOf(item):元素在数组中的位置,没有则返回 -1
- array.includes(item):数组中是否包含某个元素,返回 true 或 false
-
数组循环
- array.find( func ):返回数组中符合条件的第一个元素,没有则返回 undefined,不改变原数组
- array.map( func ):对原数组中的每个元素调用函数进行处理,返回新数组,不改变原数组
- array.forEach( func ):对数组中的每个元素调用回调函数,不改变原数组,不创建新的数组
- array.some( func ):数组中的任一元素满足函数条件,返回 true 或 false,不改变原数组
- array.every( func ):数组中的所有元素满足函数条件,返回 true 或 false,不改变原数组
- array.filter( func ):筛选数组中满足函数条件的元素,返回新数组
const numbers = [1, 2, 3, 4, 5]; const newNumbers = numbers.map(n => n > 2 ); // [false, false, true, true, true] const newNumbers = numbers.filter(n => n > 2 ); // [3, 4, 5]
-
其他
- arr.join(separator)
2. Object(对象)
- 访问属性值:obj.key、obj[key]、解构赋值(解构赋值的拷贝是浅拷贝)
- Object.entries(obj)、Object.keys(obj)、Object.values(obj)
3. Function(函数)
function add(x, y) {return x + y} // 函数声明
var add = function(x, y) {return x + y } // 匿名函数,函数存储在变量中
//ES6
const add = (x, y) => x + y; // 箭头函数
在以上代码中,x、y 均为函数的显示参数。除此之外,JavaScript 函数有个内置的对象 arguments 对象,包含了函数调用的参数数组。
三. 变量、作用域与 JS 执行顺序
- 变量:var 关键词声明变量(变量提升)。值类型占用空间固定,保存在栈中,保存和复制是值本身。引用类型保存在堆中,保存和复制的是存在栈中的指向对象的指针(浅拷贝)。
- 作用域
- 局部变量:函数体内定义,只能在当前函数内访问,函数执行完毕后销毁
- 全局变量:函数体外定义,或者函数体内不用 var 关键词定义的变量,可在全局范围内访问,页面关闭后销毁
JS 执行顺序
四. JavaScript 类(class)
- JavaScript 并不是严格意义上的面向对象语言,JavaScript 使用原型继承而不是类继承。JavaScript 在 ES6 之前并没有类的概念,而是使用构造函数和原型来定义对象。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
}
const person = new Person('John', 18);
person.sayHello();
- ES6 引入了类(class)语法糖,使得 JavaScript 也可以使用类来定义对象。新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
class Person {
constructor(name, age){ // 构造函数,初始化
this.name = name;
this.age = age;
}
sayHello() {
console.log(`Hello, my name is ${this.name}, and I am ${this.age} years old.`);
}
}
const person = new Person("John", 18);
person.sayHello();
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
sayHello() {
console.log(`Hello, my name is ${this.name}, I am ${this.age} years old, and I am in grade ${this.grade}.`);
}
}
const student = new Student("John", 18, 3);
student.sayHello();
-
ES6 的类,完全可以看作构造函数的另一种写法。事实上,类的所有方法都定义在类的 prototype 属性上面。
class Person {} typeof Person; // function Person === Person.prototype.constructor; // true person.constructor === Person.prototype.constructor; //true
原型对象和原型链
JavaScript 中,除基础数据类型外,一切都是对象。 虽然基础数据类型不是对象,但 JavaScript 在访问基础数据类型时会自动将其分装成对应的对象包装器(Number()、String() 等),使我们能够访问其属性和方法。
① const person = new Person();
:使用 new 关键词来调用构造函数创建一个实例对象。
② Person.prototype
:在 JavaScript 中,所有函数对象都有一个 prototype 属性,这个属性指向一个对象,所以也被称为原型对象。所有的 JavaScript 对象都会从 prototype(原型对象)继承属性和方法。
③ Person.prototype.constructor === Person
:在定义一个构造函数时,JavaScript 会自动为该函数创建一个 prototype 对象,并将其 constructor 属性设置为该函数本身。这样做的目的是为了方便通过实例对象访问到构造函数本身(person -> ④ -> ③ -> Person)。
④ person.__proto__ === Person.prototype
:每个 JavaScript 对象都有一个内部属性 __proto__,它指向该对象的原型。对象的原型也可以是一个对象,也有 __proto__ 属性,这样就构成了原型链。在 JavaScript 中,对象之间通过原型链实现属性和方法的继承。当我们访问一个对象的属性或方法时,如果该对象自身没有定义该属性或方法, JavaScript 会沿着原型链向上查找,直到找到该属性或方法或者到达原型链的末端。
⑤ Person.__proto__ === Function.prototype
:在 JavaScript 中,所有的函数(包括构造函数)都是 Function 对象的实例。而 Function 对象本身也是一个函数,并具有其自身的原型对象 Function.prototype。
⑥ Person.prototype.__proto__ === Object.prototype
:除了 Object.prototype,所有的构造函数的原型本身都是对象,并且它们都是 Object 构造函数的实例。
⑦ Object.prototype.__proto__ === null
:在 JavaScript 中,原型链的顶端是 Object.prototype,它是所有对象的最终原型。它没有自己的原型,也就是说它的 __proto__ 属性指向 null,这就是原型链的终点。
五. 重要概念
1. 变量提升
- 在 JavaScript 中,函数及变量的声明都将被提升到函数的最顶部,因此函数和变量可以先赋值后声明。
x = 5;
console.log(x); // 5
var x; // 变量提升从而变成:var x; x = 5; console.log(x);
- JavaScript 初始化不会提升
console.log(y); // undefined
var y = 7; // 变量提升从而变成:var y; console.log(y); y = 7;
2. this
在 JavaScript 中,this 关键字在不同的上下文中具有不同的含义。
- 全局上下文中的 this:引用全局对象,即在浏览器中是 window 对象
console.log(this); // window
-
函数上下文中的 this:this 的值取决于函数被调用的方式
- 作为普通函数调用时,this 引用全局对象
function sayHello() { console.log(this); // window } sayHello();
- 函数作为对象的方法调用时,this 引用调用该方法的对象
let obj = { name : 'John', sayHello: function() { console.log(this); // {name: 'John', sayHello: f } console.log("Hello, " + this.name); } } obj.sayHello();
- 使用 call() 或 apply() 方法可以显式地指定函数的执行上下文
function sayHello() { console.log('Hello, ' + this.name); // Hello, John } var person = { name: 'John' }; sayHello.call(person);
- 箭头函数没有自己的 this 绑定,它继承了父级作用域的 this 值
let obj = { name : 'John', sayHello: () => { console.log(this); // window } } obj.sayHello();
-
构造函数中的 this:当使用 new 关键词创建对象时,构造函数中的 this 指向新创建的实例对象
function Person(name) {
console.log(this); // Person {}
this.name = name;
console.log(this); // Person {name: 'John'}
this.sayHello = function() {
console.log(this); // Person {name: 'John', sayHello : f}
console.log('Hello, ' + this.name);
};
}
var person = new Person('John');
person.sayHello();
- 事件处理函数中的 this:引用触发事件的元素
<button onclick="console.log(this)">点击</button>
<!--打印结果为元素本身: <button οnclick="console.log(this)">点击</button> -->
3. 闭包
闭包是作用域的产物。一般来说,函数体内定义的局部变量,只能在当前函数内访问,函数执行完就会销毁。内部函数可以访问外部变量,而如果外部环境可以访问修改函数内部的变量,那就是形成了闭包。
function outer() {
var x = 0;
function inner() {
return x += 1;
}
return inner;
}
var closure = outer();
closure(); // 1
closure(); // 2
六. DOM 文档对象模型
DOM(Document Object Model):一种树状结构的对象表现方式。每个HTML元素都是树中的一个节点,而属性、文本内容等则是节点的属性。DOM树的根节点是文档节点(document),它代表整个HTML文档。DOM 提供了一组 API,使开发人员能够通过 JavaScript 来修改页面中的所有 HTML 元素和属性、CSS 样式,以及对页面中的事件做出反应。
- 查找 HTML 元素
- 通过 id 查找:
document.getElementById();
- 通过类名查找:
document.getElementByClassName();
- 通过标签查找:
document.getElementByTagName();
- 通过 CSS 选择器查找:
document.querySelectorAll();
- 通过 id 查找:
- 改变 HTML
- 改变 HTML 内容:
document.getElementById("p1").innerHTML="新文本!";
- 改变 HTML 属性:
document.getElementById("image").src="test.jpg";
- 改变 CSS 样式:
document.getElementById(id).style.color="blue";
- 改变 HTML 内容:
- DOM 事件
- DOM 分配事件:
document.getElementById("myBtn").onclick=onClick();
- 事件监听:
document.getElementById("myBtn").addEventListener("click", onClick)
- DOM 分配事件:
- 创建新的 HTML 元素
var para = document.createElement("p"); // 创建 <p> 元素
var node = document.createTextNode("这是一个新的段落。"); // 为 <p> 元素创建一个新的文本节点
para.appendChild(node); // 将文本节点添加到 <p> 元素中
var element = document.getElementById("div1");
element.appendChild(para); // 将 <p> 元素添加到已存在元素中
- 移除 HTML 元素
var parent = document.getElementById("div1");
var child = document.getElementById("p1");
parent.removeChild(child); // 移除元素时,需要知道该元素的父元素
七. BOM 浏览器对象模型
BOM(Browser Object Model):浏览器提供的一组对象和方法,用于在 JavaScript 中控制和操作浏览器窗口及其内容。
-
window 对象:表示浏览器窗口
- 浏览器窗口的内部高度或宽度:
window.innerHeight(); window.innerWidth();
- 打开或关闭窗口:
window.open(); window.close();
- 浏览器窗口的内部高度或宽度:
-
location 对象:当前窗口的 URL 信息
- 完整的 URL:
const url = location.href;
- 完整的 URL:
-
history 对象:操作浏览器的历史记录
- 加载 history 列表的前一个 URL:
history.back();
- 加载 history 列表的下一个 URL:
history.forward();
- 加载 history 列表的前一个 URL:
-
navigator 对象:提供有关浏览器的相关信息,包括浏览器名称
navigator.appName
、版本navigator.appVersion
、用户代理字符串navigator.userAgent
等。 -
存储功能
- localStorage:持久性存储,数据将一直保存在客户端,除非显示删除。不同窗口或标签页下同一域名下的页面共享相同的 localStorage 数据。
- sessionStorage:会话级存储,数据在同一会话期间有效,关闭浏览器会话后清除。每个窗口或标签页都有自己的 sessionStorage 数据,不共享。
- Cookie:可以设置过期时间,生命周期由过期时间决定,可以时持久性的或者会话级别的。Cookie 存储空间较小,会作为 HTTP 响应头的一部分传给服务端,因此可以被服务端访问和操作。不同窗口或标签页下同一域名的所有页面共享 Cookie
// sessionStorage 用法一致 localStorage.setItem(key, value); localStorage.getItem(key); localStorage.removeItem(key); localStorage.clear();