JavaScript02

函数

函数类似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}; 
      
  • 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继承

  1. 创建类
    	// 定义类
    	class Student {
    	    constructor(name, age) {
    	        this.name =name
    	        this.age = age
    	    }
    
    	    hello() {
    	        console.log(this.name + ":Hello")
    	    }
    	}
    	// 实例化对象
    	let ming = new Student('Ming', 24);
    
  2. 继承
    	// 创建子类继承父类
    	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.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)方法删除节点

    1. 获取父节点:p1.parentElementp1.parentNode
    2. 通过父节点删除要操作的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节点