函数
函数类似Java中的方法,方法在对象中,函数没有此要求。
创建函数,使用function
关键字
函数执行到return时函数结束,返回结果。
当没有return时,会返回undefined
定义方式1:
function abs(x) {
if (x>=0) {
return x
}
else {
return -x
}
}
定义方式2:function(x)是匿名函数。可以通过将结果赋值给abs,然后通过abs调用函数
let abs2 = function (x) {
if (x>=0) {
return x;
} else {
return -x;
}
}
两种定义方式等价
调用函数:abs(-10)
JS函数可以传入0或多个参数:
arguments
数组会保存传入的所有参数- 在定义函数时使用
rest
数组保存定义参数以外的参数:fuction abs(a, ...rest)
变量的作用域
变量定义存在作用域:
- 函数体内定义的变量,无法在函数外部使用(可以通过闭包实现)
- 内部函数可以访问函数外部的变量
- var声明全局变量,全局变量是绑定在window对象下的,当不用的js文件使用相同的全局变量时,会导致变量冲突
- 解决办法:每个JS文件定义自己的全局变量空间,将全局变量绑定在自己的全局变量空间下:
var space = {}; space.a = 's'; space.add = function(a, b) {return a + b};
- 解决办法:每个JS文件定义自己的全局变量空间,将全局变量绑定在自己的全局变量空间下:
- let声明局部变量
闭包
JS的函数允许将函数作为返回值。
function lazy_sum(x, y) {
return function () {return x + y};
}
let f = lazy_sum(3, 2)
f() // 5
作为返回值的内部匿名函数可以引用外部函数lazy_sum的参数和局部变量,当lazy_sum返回函数时,相关参数和变量都保存在返回的函数中,这种称为“闭包(Closure)”。
闭包的作用:
- 在没有class机制,只有函数的语言里,借助闭包,可以实现封装一个私有变量
function lazy_sum_2(x, y) { let z = 2 // z为私有变量 return function () {return x + y + z}; } let f = lazy_sum_2(3, 2) console.log(f()) // 7
- 闭包还可以实现函数内部变量的外部访问
function outer() { let out = 521; return function () {return out}; } let out = outer() console.log(out()); // 通过out()访问outer的内部变量out
方法
方法就是对象内的函数
let person = {
name: 'june',
birth: 1998,
email: '123@123.com',
sex: true,
age: function () {
let now = new Date().getFullYear();
return now - this.birth; // this表示当前对象
}
}
console.log(person.age()); // 24
函数可以通过apply()方法调用,需要传入一个对象:
function getAge() {
let now = new Date().getFullYear();
return now - this.birth;
}
let person = {
name: 'june',
birth: 1998,
email: '123@123.com',
sex: true,
age: getAge
}
console.log(person.age());
console.log(getAge.apply(person))
面向对象编程
JS对象
创建新对象有三种不同的方法:
- 使用 Object 定义并创建对象的实例
person=new Object(); // 创建对象 // 向对象添加属性或方法 person.name="John"; person.age=50; person.hello = function () {console.log('Hello...')}
- 使用函数来定义对象构造器,然后创建新的对象实例
// 构造器 function person(name,age) { this.name=name; this.age=age; this.changeName= function (name){this.name=name;} } // 创建实例 let myFather=new person("John",50); myFather.changeName("Jack");
- ES6之后引入class关键字,可以通过class创建类
// 定义类 class Student { constructor(name, age) { this.name =name this.age = age } hello() { console.log(this.name + ":Hello") } } // 实例化对象 let ming = new Student('Ming', 24);
prototype
所有的 JavaScript 对象都会从一个 prototype(原型对象)中继承属性和方法。
JS对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,不仅在该对象上搜寻,还会依次层层向上搜索,直到找到匹配的属性或到达原型链的末尾。所有JS中的对象都是位于原型链顶端的 Object 的实例。
已存在构造器函数的对象是不能添加新的属性。要添加新的属性需要修改构造器函数。
可以通过使用 prototype 属性,可以给对象的构造函数添加新的属性或方法:
Person.prototype.nationality = "Chinese";
Person.prototype.talk = function () {console.log("Talking...")}
继承
原型继承
ES6以前,JS通过原型来实现类似继承的效果,通过设置对象的原型对象来继承其属性及方法:
let person = {
name:'JE',
age:3,
walk:function () {console.log("walking...")}
}
let JS = {name: 'JS'}
// JS.walk() // TypeError: JS.walk is not a function
// 设置原型对象
JS.__proto__ = person
JS.walk()
console.log(JS.age)
class继承
- 创建类
// 定义类 class Student { constructor(name, age) { this.name =name this.age = age } hello() { console.log(this.name + ":Hello") } } // 实例化对象 let ming = new Student('Ming', 24);
- 继承
// 创建子类继承父类 class Pupil extends Student { constructor(name, age, grade) { super(name, age); this.name = name this.age = age this.grade = grade } play() { console.log(this.name + " is Playing...") } } // 实例化子类 let Ning = new Pupil('Ning', 7, 3) Ning.play() Ning.hello() // 子类可以调用父类的方法
内部对象
JS内置了一些常用的对象及方法以供使用,如Date对象、Math对象等。
Date
基本使用:
let now = new Date()
console.log(now); // 2022-03-23T06:01:14.795Z
console.log(now.getFullYear()) // 年
console.log(now.getMonth()) // 月:0-11
console.log(now.getDate()) // 日
console.log(now.getDay()) // 星期
console.log(now.getHours()) // 时
console.log(now.getMinutes()) // 分
console.log(now.getSeconds()) // 秒
console.log(now.getTime()); // 时间戳
console.log(new Date(1648015410633)); // 时间戳转为时间
JSON
JSON是一种轻量级的数据交换格式:
- JSON的层次结构简洁和清晰使得
- 易于人阅读和编写,也易于机器解析和生成,有效地提升网络传输效率
在JS中,一切皆为对象,任何JS支持的类型都可以通JSON来表示:
- 对象用{}表示
- 数组用[]表示
- 所有的键值对用key:value表示
let user = {
name: 'JE',
age: 24,
hobby:['a','b']
}
let jsonUser = JSON.stringify(user); // JS对象转换JSON字符串
let usr = JSON.parse('{"name":"JE","age":24,"hobby":["a","b"]}') // JSON字符串解析为JS对象
console.log(user) // { name: 'JE', age: 24, hobby: [ 'a', 'b' ] }
console.log(jsonUser) // {"name":"JE","age":24,"hobby":["a","b"]}
console.log(usr) // { name: 'JE', age: 24, hobby: [ 'a', 'b' ] }
Ajax
AJAX = Asynchronous JavaScript and XML(异步的 JavaScript 和 XML)。
AJAX可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页内容。
Ajax的核心对象为XMLHttpRequest(XHR)对象,XMLHttpRequest用于在后台与服务器交换数据。
具体学习:Ajax
操作BOM对象
BOM(Browser Object Module)浏览器对象模型。
window(重要)
window对象,代表浏览器
常用的属性/方法有:
window.alert('hello')
window.innerHeight
window.outerHeight
window.innerWidth
window.outerWidth
navigator(不建议使用)
navigator对象,封装了浏览器信息,并不常用这些属性来做判断,因为navigator可以被人为修改。
常用的属性有:
navigator.appVersion
navigator.userAgen
navigator.platform
screen
screen对象,包含屏幕信息
常用的属性有:
screen.width
screen.height
location(重要)
location对象,代表当前页面的URL信息
location重要的属性/方法有:
location.host
:主机location.href
:指地址location.protocol
:协议location.reload()
:刷新网页location.assign('http://lilmoon.xyz')
:设置新的指向地址
document
document对象,代表当前页面,HTML DOM树
document常用的属性/方法:
document.title
:页面标题document.getElementByID
:获取对应id的文档树节点document.getElementByClassName
:获取对应类名的文档树节点document.getElementByTagName
:获取对应标签名的文档树节点document.cookie
:获取网页的cookie,服务器可以设置cookie:httpOnly来保证安全
history(不建议使用)
history对象,包含访问过的页面
history常用的方法:
history.forward()
:前进history.back()
:后退
操作DOM对象
DOM(Document Object Module)文档对象模型。
浏览器网页是一个树形结构,常用操作:
- 更新DOM节点
- 遍历DOM节点,获取需要的DOM节点
- 删除DOM节点
- 添加新的DOM节点
- 操作DOM节点,必须先获取DOM节点
获取DOM节点
实例代码:
let h1 = document.getElementsByTagName('h1');
let p1 = document.getElementById('p1')
let p2 = document.getElementsByClassName('p2');
let father = document.getElementById('father')
let children = father.children
h1 = father.firstChild
p2 = father.lastChild
常见问题:
getElementsByClassName()
和getElementsByTagName()
方法获取的是一组元素,需要通过下标访问具体的元素- 关于获取节点结果为空,解决办法:把js引入放到节点声明下方即可。
- firstChild/lastChild返回#text或#comment
- 原因:元素内部的空白被视为文本节点。注释也被视为节点
- 解决办法:使用firstElementChild/lastElementChild返回第一个/最后一个元素节点。
JS提供了更好用的方法:
querySelector(selectors)
和querySelectorAll(selectors)
方法:
- selectors是一个CSS选择器字符串
querySelector(selectors)
返回匹配指定选择器的第一个元素querySelectorAll(selectors)
方法返回匹配指定选择器的所有元素
更多信息见MDN
更新DOM节点
更新DOM节点的内容:
- 通过
element.innerText = 'Hello'
修改文本内容 - 通过
element.innerHTML = '<em>Hello</em>'
:可以解析HTML标签
更新DOM节点的样式属性,属性值要用字符串表示:
element.style.color = 'skyblue'
element.style.fontSize = '32px'
element.style.backgroundColor = 'black'
删除DOM节点
删除节点的两种方法:
-
直接通过自身的remove()方法删除节点
let p1 = document.getElementById('p1') p1.remove()
-
通过父节点的removeChild(child)方法删除节点
- 获取父节点:
p1.parentElement
或p1.parentNode
- 通过父节点删除要操作的DOM节点:
father.removeChild(p1)
或father.removeChild(father.children[1])
- 获取父节点:
插入节点
创建节点
let newP = document.createElement('p');
newP.setAttribute('class', 'hello hi') // 设置节点属性
newP.innerHTML = '<em>New P</em>' // 设置节点内容
追加节点
let js = document.getElementById('js')
let list = document.getElementById('list')
list.append(js, newP) // append方法可以一次追加多个节点
list.appendChild(js) // appendChild方法一次只能追加一个节点
注意:追加获取到的已有的节点时,相当于改变其位置
插入节点:
let ee = document.getElementById('ee')
list.insertBefore(js, ee)
list.insertBefore(js, ee)
表示在list的子节点ee之前插入js节点