1.原型
<script>
/*
原型
+ 解决问题
=> 当你需要给实例对象添加方法
=> 直接书写在构造函数体内
=> 这个行为并不好
=> 我们的原型就是解决了这个问题
+ 不好的原因
=> 当我把方法书写在构造函数体内
=> 每次创建实例的时候, 都会创建一个函数数据类型
=> 多个函数方法, 一模一样, 但是占据了多分存储空间
*/
function Person(name, age) {
// 向实例对象内添加属性
this.name = name
this.age = age
// 向实例对象内添加方法
// 在构造函数体内直接向实例对象添加方法, 这个行为并不好
this.sayHi = function () { console.log('hello world') }
}
// 创建一个实例
var p1 = new Person('Jack', 18)
// 创建第二个实例
var p2 = new Person('Rose', 20)
console.log(p1)
console.log(p2)
console.log(p1.sayHi)
console.log(p2.sayHi)
console.log(p2.sayHi === p1.sayHi)
</script>
2.解决问题
<script>
解决问题
+ 原型
=> 概念: 每一个构造函数天生自带一个 prototype 属性, 是一个对象数据类型
=> 概念: 每一个对象天生自带一个属性 __proto__, 指向所属构造函数的 prototype
=> 概念: 当你访问对象的成员的时候, 首先在自己身上查找, 如果没有, 自动去到 __proto__ 上查找
+ 如何解决问题
=> 我们把需要添加给实例的方法, 放在构造函数的原型(prototype)上
=> 就可以有实例进行访问使用
+ 原型:
=> 构造函数天生自带的一个 prototype
=> 作用: 有构造函数添加方法, 专门给实例对象使用
// 当函数被书写完毕以后
// 就会有 prototype 出现
// function Person() {}
// // 直接向 prototype 内添加一些成员
// Person.prototype.a = 100
// Person.prototype.b = 200
// console.log(Person.prototype)
// // 创建一个实例对象
// // p1 所属的构造函数就是 Person
// // p1.__proto__ === Person.prototype
// var p1 = new Person()
// console.log(p1.__proto__ === Person.prototype)
// console.log(p1.__proto__)
// // 当你访问 p1 的 a 成员
// // 因为当你访问 p1.a 的时候, 自己没有, 会自动去自己的 __proto__ 上查找
// // 又因为 自己的__proto__ 就是 Perosn.prototype
// // 所以, 其实就是去到 Person.prototype 上查找
// console.log(p1.a)
function Person(name, age) {
// 向实例对象上添加属性
this.name = name
this.age = age
// 向实例对象上添加方法
// this.sayHi = function () { console.log('hello world') }
}
// 把想添加给实例对象的方法, 书写原型上
Person.prototype.sayHi = function () { console.log('hello world') }
// 创建实例对象
// p1 和 p2 所属的构造函数都是 Person
// p1.__proto__ === Person.prototype
// p2.__proto__ === Person.prototype
var p1 = new Person('Jack', 18)
var p2 = new Person('Rose', 20)
console.log(p1)
console.log(p2)
console.log(p1.__proto__ === Person.prototype)
console.log(p2.__proto__ === Person.prototype)
// 当你访问 p1 的sayHi 的时候
// 自己没有, 回去自己的 __proto__ 上找
console.log(p1.sayHi)
// 当你访问 p2 的sayHi 的会搜
// 自己没有, 会去自己的 __proto__ 上找
console.log(p2.sayHi)
// 因为 p1.__proto__ 和 p2.__proto__ 是一个对象空间
// p1 和 p2 的 sayHi 是一个
console.log(p1.sayHi === p2.sayHi)
</script>
3.原型链
<script>
问题1: 实例对象身上的 __proto__ 指向谁 ?
=> 指向所属构造函数的 prototype
=> p1 所属的构造函数是 Person
=> p1.__proto__ 指向 Person.prototype
问题2: Person.prototype 的 __proto__ 指向谁 ?
=> Person.prototype 所属的构造函数是谁
=> 因为 Perosn.prototype 是一个对象数据类型(Object)
=> 在 JS 内所有的 Object 数据类型都是属于 Object 这个内置构造函数
=> Person.prototype 是属于 Object 这个内置构造函数的
=> Person.prototype 的 __proto__ 指向 Object.prototype
问题3: Person 的 __proto__ 指向谁 ?
=> Person 是一个函数, 函数本身也是一个对象, 就会有 __proto__
=> 在 JS 内, 所有的函数都是属于内置构造函数 Function 的实例
=> Person.__proto__ 指向 Function.prototype
问题4: Object.prototype 的 __proto__ 指向谁 ?
=> Object.prototype 是一个对象数据类型, 只要是对象, 都是数据 Object 这个内置构造函数的
=> 注意: Object.prototype 在 JS 内叫做顶级原型, 不在有 __proto__ 了
=> Object.prototype 的 __proto__ 指向 null
问题5: Object 的 __proto__ 指向谁 ?
=> Object 是内一个内置构造函数, 同时也是一个函数, 同时也是一个对象
=> 在 JS 内, 所以的函数都是属于内置构造函数 Function 的实例
=> Object 也是 Function 的实例
=> Object.__proto__ 指向 Function.prototype
问题6: Function.prototype 的 __proto__ 指向谁 ?
=> Function.prototype 也是一个对象数据类型
=> 只要是对象数据类型都是 Object 的实例
=> Function.prototype 的 __proto__ 指向 Object.prototype
问题7: Function 的 __proto__ 指向谁 ?
=> Function 也是一个内置构造函数, 也是一个函数
=> 在 JS 内, 所有的函数都是属于内置构造函数 Function 的实例
=> Function 自己是自己的构造函数
=> Function 自己是自己的实例对象
=> Function 所属的构造函数的是 Function
原型链
+ 用 __proto__ 串联起来的对象链状结构
+ 注意: 使用 __proto__
+ 每一个对象数据类型, 都有一个属于自己的原型链
+ 作用: 为了访问对象成员
对象访问机制:
+ 当你需要访问对象的成员的时候
+ 首先在自己身上查找, 如果有直接使用
+ 如果没有, 会自动去 __proto__ 上查找
+ 如果还没有, 就再去 __proto__ 上查找
+ 直到 Object.prototype 都没有, 那么返回 undefined
function Person() {}
var p1 = new Person()
</script>
1.ES6定义变量
<script>
// 1. 预解析
// console.log(num)
// var num = 100
// console.log(num)
// 定义之前使用 let 声明的变量会报错
// console.log(num2)
// let num2 = 200
// console.log(num2)
// 定义之前使用 const 声明的变量会报错
// console.log(num3)
// const num3 = 300
// console.log(num3)
// 2. 重复变量名
// var n1 = 100
// var n1 = 200
// console.log(n1)
// let n2 = 100
// let n2 = 200
// const n3 = 100
// const n3 = 200
// 3. 块级作用域
// 任何一个可以执行代码段的 {} 都会限制该变量的使用范围
// if (true) {
// var num = 100
// console.log(num)
// }
// console.log(num)
// if (true) {
// // 因为这个 num 使用 let 关键字定义的
// // 所以只能在这个 if 的 {} 内使用
// let num = 100
// console.log(num)
// }
// console.log(num)
// if (true) {
// // 因为这个 num 使用 const 关键字定义的
// // 所以只能在这个 if 的 {} 内使用
// const num = 100
// console.log(num)
// }
// console.log(num)
// 4. 定义时不赋值
// let num
// console.log(num)
// num = 100
// console.log(num)
// 使用 const 的时候, 声明时必须赋值
// const num
// console.log(num)
// num = 100
// console.log(num)
// 5. 修改
// let num = 100
// console.log(num)
// num = 200
// console.log(num)
const num = 100
console.log(num)
// 你试图修改 num 的值, 但是因为是 const 定义的, 不能修改
num = 200
console.log(num)
</script>
2.ES6的箭头函数
<script>
// var fn1 = function () { console.log('我是 fn1 函数') }
// fn1()
// var fn2 = () => { console.log('我是 fn2 函数') }
// fn2()
/*
箭头函数的特殊之处
1. 箭头函数某些时候可以省略 ()
=> 当你的形参只有一个的时候, 可以不写 ()
2. 箭头函数某些时候可以省略 {}
=> 当你的代码只有一句话的时候, 可以不写 {}
=> 并且会自动把这一句话的结果当做函数的返回值
3. 箭头函数内没有 arguments
4. 箭头函数内没有 this
=> 箭头函数内的 this 就是外部作用域的 this
*/
// 1.
// var fn1 = () => { console.log('我没有形参') }
// fn1()
// var fn2 = a => { console.log('我一个形参 : ', a) }
// fn2(100)
// var fn3 = (a, b) => { console.log('我两个形参: ', a, b) }
// fn3(100, 200)
// 2.
// var fn1 = (a, b) => a + b
// console.log(fn1(10, 20))
// 3.
// var fn1 = () => {
// console.log(arguments)
// }
// fn1(100, 200, 300)
// var fn2 = function () {
// console.log(arguments)
// }
// fn2(100, 200, 300)
// 4.
var obj = {
fn: function () { console.log(this) },
fn2: () => { console.log(this) }
}
obj.fn() // this 因为 fn 函数被 obj 调用, 所以 this 是 obj
obj.fn2() // 因为是箭头函数, 内部没有 this, 就是外部作用域的 this
</script>
3.ES6的函数默认值
<script>
function fn(a = 100, b = 200) {
// 表示声明了两个形参
// 其中 a 设置默认值为 100
// 其中 b 设置默认值为 200
console.log('a : ', a)
console.log('b : ', b)
console.log('---------------------')
}
// 两个实参都没有传递, 都会使用默认值
fn()
// 给 a 进行了赋值, a 就使用 10
// b 继续使用默认值 200
fn(10)
// 给 a 进行了赋值, a 就使用 10
// 给 b 进行了赋值, b 就使用 20
fn(10, 20)
</script>
4.ES6 解构赋值
<script>
// 1. 解构数组
// var arr = [ 'hello', 'world' ]
// // 开始解构
// // 注意: 解构数组使用 []
// // a 获取的内容就是 arr[0]
// // b 获取的内容就是 arr[1]
// var [ a, b ] = arr
// console.log(a)
// console.log(b)
// 2. 解构对象
var obj = { name: 'Jack', age: 18 }
// 开始解构
// 注意: 解构对象使用 {}
// 表示定义一个叫做 name 的变量, 获取的是 obj 内一个叫做 name 的成员的值
// var { name, age, a } = obj
// console.log(name)
// console.log(age)
// console.log(a)
// var a = obj.age
// console.log(a)
// 相当于定义变量 a 从 obj 内获取一个叫做 a 的成员的值
// var { a } = obj
// console.log(a)
// 可以起一个别名
// 相当于顶一个 a 变量, 从 obj 内获取一个叫做 age 的值
var { age: a } = obj // => var a = obj.age
console.log(a)
</script>
5.ES6的模板字符串
<script>
+ 其实, 就是 ES6 内新增的定义字符串的方式
+ 以前:
=> var str = '内容'
=> var str = "内容"
+ 现在:
=> var str = `内容`
区别:
1. 可以换行书写
2. 可以直接在字符串内解析变量
=> 当你需要解析变量的时候, 直接书写 ${ 变量 }
// 1.
// var s1 = 'hello world'
// var s2 = "hello world"
// var s3 = `
// hello
// world
// `
// console.log(s1)
// console.log(s2)
// console.log(s3)
// 2.
var age = 18
var s1 = `我叫前端小灰狼, 今年 ${age} 岁`
console.log(s1)
var s2 = '我叫前端小灰狼, 今年 ${age} 岁'
console.log(s2)
var s3 = "我叫前端小灰狼, 今年 ${age} 岁"
console.log(s3)
</script>
6.ES6 的展开运算符
<script>
/*
+ ...
+ 作用: 展开数组的[] 或者展开对象的 {}
*/
// console.log(100, 200, 300, 400)
// var arr = [ 100, 200, 300, 400 ]
// console.log(arr)
// console.log(...arr)
// 作用1: 合并数组
// var arr1 = [ 10, 20 ]
// var arr2 = [ 30, 40 ]
// var arr3 = [ 50, 60, 70 ]
// var arr4 = [ 80, 90 ]
// var arr5 = [ ...arr1, ...arr2, ...arr3, ...arr4 ]
// console.log(arr5)
// 作用2: 给函数传递参数
// var arr1 = [ 10, 20, 17, 7, 31, 22, 12 ]
// // var max = Math.max(10, 20, 17, 7, 31, 22, 12)
// // var max = Math.max(arr1)
// var max = Math.max(...arr1)
// console.log(max)
// 展开对象
var obj = { name: 'Jack', age: 18 }
console.log(obj)
// 作用1: 用来复制对象
// 注意: 展开书写的顺序问题, 在有相同成员的时候
var obj2 = {
gender: '男',
...obj,
name: 'Rose',
}
console.log(obj2)
</script>
7.ES6 的类语法
<script>
/*
ES6 的类语法
+ 语法:
class 类名 {
// 原先 ES5 内的构造函数体
constructor () {}
// 直接书写原型上的方法即可
// 书写静态属性和方法, 需要加上一个 static 关键字即可
}
+ 注意: 必须和 new 关键字连用
=> 不和 new 关键字连用, 会直接报错
*/
// function Person(name, age) {
// this.name = name
// this.age = age
// }
// // 原型添加一个方法
// // 2. 原型上的方法, 目的是为了给 实例使用
// Person.prototype.sayHi = function () { console.log('hello world') }
// // 书写静态属性和方法
// Person.a = 100
// Person.go = function () { console.log('跑起来') }
// var p1 = new Person('jack', 18)
// console.log(p1)
// p1.sayHi()
// // 1. 构造函数本质还是一个函数, 可以不和 new 关键字连用
// var p2 = Person('Rose', 20)
// console.log(p2)
// console.log(Person.a)
// Person.go()
// 类的书写
class Person {
constructor (name, age) {
// 这里按照 ES5 的构造函数体书写
this.name = name
this.age = age
}
// 直接书写原型上的方法即可
sayHi () { console.log('你好 世界') }
// 静态属性
static a = 100
// 静态方法
static go () { console.log('running') }
}
var p1 = new Person('张三', 18)
console.log(p1)
p1.sayHi()
// 使用静态属性和静态方法
Person.go()
console.log(Person.a)
</script>
1.第一次尝试 ajax
<script>
// 1. 创建一个 ajax 对象
var xhr = new XMLHttpRequest()
// 2. 配置本次的请求信息
// 请求方式: 按照接口文档来进行书写
// 请求地址: 按照接口文档来进行书写
// 是否异步: 默认是 true 表示异步请求, 选填为 false, 表示同步请求
xhr.open('GET', 'http://localhost:8888/test/first', true)
// 3. 配置一个请求完成后触发的事件
// 请求完整: 本次请求发送出去, 服务器接收到了我们的请求, 并且服务器返回的信息已经回到了浏览器
xhr.onload = function () {
// 如何拿到后端返回的信息
// 语法: xhr.responseText
console.log(xhr.responseText)
}
// 4. 把本次请求发送出去
xhr.send()
</script>
2.第二次测试 ajax
<script>
// 1. 创建ajax 对象
var xhr = new XMLHttpRequest()
// 2. 配置本次的请求信息
xhr.open('GET', 'http://localhost:8888/test/second', true)
// 3. 配置请求完成的事件
xhr.onload = function () {
// 当后端返回的是 json 格式字符串的时候, 我们需要进行单独的解析
// 语法: JSON.parse(json格式字符串)
// 返回值: 解析好的 js 格式的数据
var res = JSON.parse(xhr.responseText)
console.log(res)
}
// 4. 发送出去
xhr.send()
</script>
3.GET 和 POST 请求
<script>
// 1. GET 请求
// var xhr = new XMLHttpRequest()
// // 需要携带参数
// // 因为是 GET 请求, 直接在地址后面进行参数的书写
// xhr.open('GET', 'http://localhost:8888/test/third?name=前端小灰狼&age=18', true)
// xhr.onload = function () {
// console.log(JSON.parse(xhr.responseText))
// }
// xhr.send()
// 2. POST 请求
var xhr = new XMLHttpRequest()
// 注意: 因为是 POST 请求, 不需要在地址后面拼接参数
xhr.open('POST', 'http://localhost:8888/test/fourth', true)
xhr.onload = function () {
console.log(JSON.parse(xhr.responseText))
}
// 注意: 当你发送 POST 请求, 并且需要携带参数的时候, 需要进行特殊说明
// 语法: xhr.setRequestHeader('content-type', 你传递参数的格式)
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
// send 后面的() 就是书写请求体的位置
xhr.send('name=前端小灰狼&age=18')
</script>
4.登录案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<style>
* {
margin: 0;
padding: 0;
}
form {
width: 500px;
padding: 20px;
margin: 50px auto;
border: 3px solid pink;
display: flex;
flex-direction: column;
font-size: 30px;
padding-top: 50px;
position: relative;
}
form > span {
position: absolute;
left: 50%;
top: 5px;
transform: translateX(-50%);
width: 100%;
text-align: center;
color: red;
display: none;
}
form > label {
height: 50px;
}
form > label > input {
font-size: 24px;
height: 40px;
padding-left: 20px;
}
</style>
</head>
<body>
<form>
<span class="error">用户名或者密码错误!!</span>
<label>
用户名 : <input class="username" type="text">
</label>
<label>
密 码 : <input class="password" type="text">
</label>
<button>登录</button>
</form>
<script>
/*
案例 - 登录
分析需求:
+ 问题1: 什么时候进行发送请求 ?
=> 点击登录按钮的时候
=> 需要给 form 标签绑定一个表单提交事件
+ 问题2: 需要拿到哪些信息 ?
=> 需要拿到用户填写的用户名和密码
+ 问题3: 需要如何发送给后端 ?
=> 按照接口文档的规范进行发送
+ 问题4: 请求完成以后, 我们需要做什么 ?
=> 根据后端返回的信息, 进行一些后续的操作
=> 如果后端返回的信息是登录成功, 那么我们进行页面跳转
=> 如果后端返回的是登录失败, 那么我们提示用户错误
*/
// 0. 获取元素
// 0-1. form 标签
var loginForm = document.querySelector('form')
// 0-2. 用户名文本框
var nameInp = document.querySelector('.username')
// 0-3. 密码文本框
var pwdInp = document.querySelector('.password')
// 0-4. 错误提示文本
var errBox = document.querySelector('.error')
// 1. 给 form 标签绑定一个表单提交事件
loginForm.onsubmit = function (e) {
// 注意: 阻止表单的默认提交行为
e.preventDefault()
// 2. 拿到填写的用户名和密码
var name = nameInp.value
var pwd = pwdInp.value
// 2-2. 验证用户名和密码
if (!name || !pwd) return alert('请完整填写表单')
// 3. 发送 ajax 请求
var xhr = new XMLHttpRequest()
xhr.open('POST', 'http://localhost:8888/users/login', true)
xhr.onload = function () {
// 因为后端返回的是 json 格式数据
var res = JSON.parse(xhr.responseText)
console.log(res)
// 进行条件判断
if (res.code === 0) {
// 登录失败了
errBox.style.display = 'block'
} else {
// 登录成功了
window.location.href = './home.html'
}
}
// 注意: POST 请求携带参数需要提前说明
xhr.setRequestHeader('content-type', 'application/x-www-form-urlencoded')
// 因为 POST 请求携带参数是在请求体内
xhr.send('username=' + name + '&password=' + pwd)
}
</script>
</body>
</html>