blog: 添加React学习笔记
This commit is contained in:
parent
d9384449a5
commit
108e7973bf
|
|
@ -20,6 +20,7 @@ module.exports = [
|
|||
{ text: '《JavaScript高级程序设计》笔记', link: '/note/js/' },
|
||||
{ text: '《ES6 教程》笔记', link: '/note/es6/' },
|
||||
{ text: '《Vue》笔记', link: '/note/vue/' },
|
||||
{ text: '《React》笔记', link: '/note/react/' },
|
||||
{
|
||||
text: '《TypeScript 从零实现 axios》',
|
||||
link: '/note/typescript-axios/',
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
---
|
||||
pageComponent:
|
||||
pageComponent:
|
||||
name: Catalogue
|
||||
data:
|
||||
data:
|
||||
key: 《ES6 教程》笔记
|
||||
imgUrl: https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200112160453.png
|
||||
description: 本章内容为博主在原教程基础上添加学习笔记,教程版权归原作者所有。来源:<a href='https://es6.ruanyifeng.com/' target='_blank'>ES6教程</a>
|
||||
title: 《ES6 教程》笔记
|
||||
date: 2020-01-12 15:49:22
|
||||
permalink: /note/es6
|
||||
permalink: /note/es6/
|
||||
article: false
|
||||
comment: false
|
||||
editLink: false
|
||||
author:
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
---
|
||||
pageComponent:
|
||||
pageComponent:
|
||||
name: Catalogue
|
||||
data:
|
||||
data:
|
||||
key: 《Vue》笔记
|
||||
imgUrl: https://cdn.jsdelivr.net/gh/xugaoyi/image_store/blog/20200204143633.png
|
||||
description: 本章内容是博主的Vue学习笔记,以官方文档为准。
|
||||
description: 本章内容是博主的Vue学习笔记,非教程文档,请以官方文档为准。
|
||||
title: 《Vue》笔记
|
||||
date: 2020-02-04 12:16:12
|
||||
permalink: /note/vue
|
||||
permalink: /note/vue/
|
||||
article: false
|
||||
comment: false
|
||||
editLink: false
|
||||
author:
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
---
|
||||
pageComponent:
|
||||
name: Catalogue
|
||||
data:
|
||||
key: 《React》笔记
|
||||
imgUrl: data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9Ii0xMS41IC0xMC4yMzE3NCAyMyAyMC40NjM0OCI+CiAgPHRpdGxlPlJlYWN0IExvZ288L3RpdGxlPgogIDxjaXJjbGUgY3g9IjAiIGN5PSIwIiByPSIyLjA1IiBmaWxsPSIjNjFkYWZiIi8+CiAgPGcgc3Ryb2tlPSIjNjFkYWZiIiBzdHJva2Utd2lkdGg9IjEiIGZpbGw9Im5vbmUiPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIi8+CiAgICA8ZWxsaXBzZSByeD0iMTEiIHJ5PSI0LjIiIHRyYW5zZm9ybT0icm90YXRlKDYwKSIvPgogICAgPGVsbGlwc2Ugcng9IjExIiByeT0iNC4yIiB0cmFuc2Zvcm09InJvdGF0ZSgxMjApIi8+CiAgPC9nPgo8L3N2Zz4K
|
||||
description: 本章内容是博主的React学习笔记,非教程文档,请以官方文档为准。
|
||||
title: 《React》笔记
|
||||
date: 2021-03-25 19:50:12
|
||||
permalink: /note/react/
|
||||
article: false
|
||||
comment: false
|
||||
editLink: false
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -6,7 +6,7 @@ categories:
|
|||
- 前端
|
||||
- 学习笔记
|
||||
tags:
|
||||
-
|
||||
- TypeScript
|
||||
---
|
||||
# TypeScript 学习笔记
|
||||
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@
|
|||
title: 小程序笔记
|
||||
date: 2019-12-25 14:27:01
|
||||
permalink: /note/wx-miniprogram
|
||||
tags:
|
||||
- null
|
||||
categories:
|
||||
tags:
|
||||
- 小程序
|
||||
categories:
|
||||
- 前端
|
||||
- 学习笔记
|
||||
author:
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -276,7 +276,7 @@ weUI是一套同微信原生视觉体验一致的基础样式库
|
|||
|
||||
#### 数据类型
|
||||
|
||||
String 字符串
|
||||
String 字符串
|
||||
|
||||
Number 数字
|
||||
|
||||
|
|
@ -334,7 +334,7 @@ const testDB = wx.cloud.database({
|
|||
|
||||
|
||||
|
||||
#### serverless(无服务)
|
||||
#### serverless(无服务)
|
||||
|
||||
概念:函数即服务,当需要后端服务的时候,不需要关心后端的IP地址、域名,只需要像调用普通函数一样既可以实现调用。
|
||||
|
||||
|
|
@ -544,7 +544,7 @@ pages 设置页面 ,设置后会自动在pages目录下生成相应的目录
|
|||
type: Object // 数据类型
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
//子组件的wxml文件可直接引入数据{{playlist}}
|
||||
```
|
||||
|
||||
|
|
@ -562,7 +562,7 @@ key的值不建议使用index,因为当数据发生变化会dom结构产生变
|
|||
<image src="{{item.url}}" mode="widthFix" class="img"></image>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
|
||||
<view class="playlist-container">
|
||||
<block wx:for="{{playlist}}" wx:key="_id">
|
||||
<!-- 参数:playlist 自定义名称,传入组件的数据 -->
|
||||
|
|
@ -595,7 +595,7 @@ cloudfunctions目录 右键 `新建 Node.js 云函数` > 输入目录名 `getPl
|
|||
|
||||
在云函数中向第三方服务器发送请求要依赖第三方库
|
||||
|
||||
**安装依赖包**
|
||||
**安装依赖包**
|
||||
|
||||
云函数目录 `getPlaylist` 右键 `在终端打开` 打开命令行 输入命令:
|
||||
|
||||
|
|
@ -663,7 +663,7 @@ exports.main = async (event, context) => {
|
|||
*/
|
||||
|
||||
// const list = await playlistCollection.get() // 获取数据库集合的数据 (因为有条数限制,不直接用此方法)
|
||||
|
||||
|
||||
// 突破条数限制 (为了读取到全部数据然后与第三方服务器获取的数据进行对比去重)
|
||||
const countResult = await playlistCollection.count() // 获取数据总条数 返回为对象
|
||||
const total = countResult.total // 取得总条数
|
||||
|
|
@ -683,7 +683,7 @@ exports.main = async (event, context) => {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// 获取第三方服务器端数据
|
||||
const playlist = await rp(URL).then((res) => {
|
||||
return JSON.parse(res).result
|
||||
|
|
@ -747,9 +747,9 @@ exports.main = async (event, context) => {
|
|||
.orderBy('createTime', 'desc').get().then((res) => {
|
||||
return res.data
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
return app.serve() // 必需返回
|
||||
}
|
||||
|
|
@ -824,9 +824,9 @@ page页面js中有这两个函数:
|
|||
onReachBottom: function() {
|
||||
this._getPlaylist()
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
下拉刷新请求完数据后
|
||||
wx.stopPullDownRefresh() // 停止下拉刷新动画
|
||||
```
|
||||
|
|
@ -874,7 +874,7 @@ const TcbRouter = require('router'); // 必需
|
|||
|
||||
exports.main = (event, context) => {
|
||||
const app = new TcbRouter({ event });// 必需
|
||||
|
||||
|
||||
// app.use 表示该中间件会适用于所有的路由(全局中间件) 非必需
|
||||
app.use(async (ctx, next) => { // 这个中间件表示所有路由都会调用到,而路由中间件为单独调用
|
||||
ctx.data = {}; // 获取要传给小程序端的数据
|
||||
|
|
@ -981,7 +981,7 @@ wx.setNavigationBarTitle({
|
|||
|
||||
|
||||
```json
|
||||
// 需要在app.json配置,才能使用后台音乐播放的能力
|
||||
// 需要在app.json配置,才能使用后台音乐播放的能力
|
||||
|
||||
"requiredBackgroundModes": ["audio", "location"]
|
||||
```
|
||||
|
|
@ -1128,7 +1128,7 @@ methods: {
|
|||
子组件1js:
|
||||
// 触发自定义事件 向父组件传值, 参数x(可选,传递给父组件的参数,可以是对象或其他)
|
||||
this.triggerEvent('自定义事件名1', 参数x)
|
||||
|
||||
|
||||
|
||||
|
||||
子组件2js:
|
||||
|
|
@ -1177,7 +1177,7 @@ wx.getSystemInfo({
|
|||
onLaunch: function () {
|
||||
this.globalData = {// 设置全局属性、方法
|
||||
test: 0
|
||||
}
|
||||
}
|
||||
},
|
||||
setGlobalData(dataItem, val) { // 设置全局属性
|
||||
this.globalData[dataItem] = val
|
||||
|
|
@ -1239,11 +1239,11 @@ components内部的组件无法直接调用外部的样式。可通过以下方
|
|||
'iconfont', // 对应的是上面等号前面的名称
|
||||
'icon-sousuo'
|
||||
],
|
||||
|
||||
|
||||
子组件wxml: 即可实现调用组件外的样式
|
||||
<i class="iconfont icon-sousuo" />
|
||||
|
||||
|
||||
|
||||
|
||||
注意:如果想在组件内部再次修改样式,不能够引用外部传进来的class名称进行修改,可以另起一个class名称进行修改。
|
||||
```
|
||||
|
||||
|
|
@ -1276,7 +1276,7 @@ Component({
|
|||
<view>插槽内容</view>
|
||||
</view>
|
||||
</组件标签>
|
||||
|
||||
|
||||
组件内部定义slot标签:
|
||||
<view>
|
||||
<!-- slot插槽 -->
|
||||
|
|
@ -1289,7 +1289,7 @@ Component({
|
|||
**如果需要实现多个插槽**
|
||||
|
||||
```
|
||||
|
||||
|
||||
父组件调用传入插槽内容:
|
||||
<组件标签>
|
||||
<view slot="slot2">
|
||||
|
|
@ -1307,8 +1307,8 @@ Component({
|
|||
options: {// 设置
|
||||
multipleSlots: true // 打开多个插槽功能
|
||||
},
|
||||
|
||||
|
||||
|
||||
|
||||
组件内部定义slot标签:
|
||||
<view>
|
||||
<!-- slot插槽 具名插槽-->
|
||||
|
|
@ -1337,7 +1337,7 @@ options: {// 设置
|
|||
}
|
||||
})
|
||||
} else { // 未授权
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
})
|
||||
|
|
@ -1444,8 +1444,8 @@ wx.chooseImage({
|
|||
<icon class="iconfont icon-shanchu" bindtap="onDelImage" data-index="{{index}}"></icon>
|
||||
</view>
|
||||
</block>
|
||||
|
||||
|
||||
|
||||
|
||||
// 删除图片
|
||||
onDelImage(event) {
|
||||
// event.target.dataset.index 获取标签属性data-index的值
|
||||
|
|
@ -1499,7 +1499,7 @@ wx.chooseImage({
|
|||
})
|
||||
/**
|
||||
* 实现思路及步骤:
|
||||
* 1、图片 -> 上传 云存储 -> 生成 图片fineID(云文件ID)
|
||||
* 1、图片 -> 上传 云存储 -> 生成 图片fineID(云文件ID)
|
||||
* 2、数据 -> 录入 云数据库
|
||||
* 数据包括:文字内容、图片fineID、昵称、头像、发布时间、openId(用户唯一标识,在插入数据库是系统会自动添加_openId字段,不需要另外插入)
|
||||
*/
|
||||
|
|
@ -1528,7 +1528,7 @@ wx.chooseImage({
|
|||
})
|
||||
promiseArr.push(p)
|
||||
})
|
||||
|
||||
|
||||
// 存入云数据库
|
||||
Promise.all(promiseArr).then((res) => {
|
||||
db.collection('blog').add({
|
||||
|
|
@ -1610,7 +1610,7 @@ formatTime(new Date('Wed Aug 28 2019 16:23:06 GMT+0800 (中国标准时间)'))
|
|||
|
||||
#### 阻止事件冒泡
|
||||
|
||||
`bind` 和 `catch` 都可以绑定事件,它们的区别是 `bind` 有事件冒泡,而 `catch` 没有
|
||||
`bind` 和 `catch` 都可以绑定事件,它们的区别是 `bind` 有事件冒泡,而 `catch` 没有
|
||||
|
||||
|
||||
|
||||
|
|
@ -1666,7 +1666,7 @@ formatTime(new Date('Wed Aug 28 2019 16:23:06 GMT+0800 (中国标准时间)'))
|
|||
.orderBy('createTime', 'desc').get().then((res) => {
|
||||
return res.data
|
||||
})
|
||||
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
|
|
@ -1780,7 +1780,7 @@ formatTime(new Date('Wed Aug 28 2019 16:23:06 GMT+0800 (中国标准时间)'))
|
|||
|
||||
##### 第三种:N的数量巨大 几百成千上万个
|
||||
|
||||
**每个 N 都存储 1 的 id**
|
||||
**每个 N 都存储 1 的 id**
|
||||
|
||||
如新浪博客中的一条博客下面有几千条评论
|
||||
|
||||
|
|
@ -1875,7 +1875,7 @@ exports.main = async (event, context) => {
|
|||
page: `/pages/blog-comment/blog-comment?blogId=${event.blogId}`, // 用户点击推送消息打开的页面
|
||||
data: { // 模板的内容,keyword为在公众平台设置模板时对应的字段
|
||||
keyword1: { // 评价内容
|
||||
value: event.context
|
||||
value: event.context
|
||||
},
|
||||
keyword2: { // 评价时间
|
||||
value: event.time
|
||||
|
|
@ -2021,7 +2021,7 @@ wx.getUserInfo({
|
|||
})
|
||||
```
|
||||
|
||||
在未授权的情况下需要用户先授权:
|
||||
在未授权的情况下需要用户先授权:
|
||||
|
||||
```js
|
||||
// 判断用户是否授权
|
||||
|
|
@ -2045,12 +2045,12 @@ wx.getUserInfo({
|
|||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
授权按钮
|
||||
<button class="login" open-type="getUserInfo" bindgetuserinfo="onGetUserInfo">获取微信授权信息</button>
|
||||
|
||||
|
||||
|
||||
|
||||
onGetUserInfo(event) { // 获取用户信息
|
||||
const userInfo = event.detail.userInfo
|
||||
if (userInfo) { // 用户允许授权
|
||||
|
|
@ -2062,7 +2062,7 @@ wx.getUserInfo({
|
|||
this.triggerEvent('loginFail')
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
> 注意:上面这种方式没有获取到openId
|
||||
|
|
@ -2293,7 +2293,7 @@ onLoad: function (options) {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
```js
|
||||
// 云函数入口函数
|
||||
|
|
@ -2310,7 +2310,7 @@ exports.main = async (event, context) => {
|
|||
// },
|
||||
// isHyaline: true // 是否透明
|
||||
})
|
||||
|
||||
|
||||
// result为二进制数据, 先上传到云存储
|
||||
|
||||
// 上传云存储
|
||||
|
|
@ -2472,7 +2472,7 @@ checkUpate(){
|
|||
|
||||
vue-admin-template <---通过ajax--> 基于Koa2;HTTP API 或 tcb-admin-node ---->云函数、云数据库、云存储
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -2527,7 +2527,7 @@ app.use(async (ctx) => {
|
|||
const port = 3000
|
||||
app.listen(port, () => { // 端口号,开启服务后的回调函数
|
||||
console.log(chalk.green(`> 服务已开启,访问:http://localhost:${port}`))
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -2716,9 +2716,9 @@ app.use(koaBody({
|
|||
|
||||
```js
|
||||
router.post('/updatePlaylist', async (ctx, next) => {
|
||||
|
||||
|
||||
const params = ctx.request.body // post请求获取前端传来的数据,需安装和配置koa-body
|
||||
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
|
|
@ -2736,7 +2736,7 @@ router.get('/list', async (ctx, next) => {
|
|||
const query = `db.collection('swiper').get()`
|
||||
const res = await callCloudDB(ctx, 'databasequery', query)
|
||||
console.log(res)
|
||||
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
|
|
@ -2749,14 +2749,3 @@ router.get('/list', async (ctx, next) => {
|
|||
#### 后端上传图片到云存储
|
||||
|
||||
[文件上传](https://developers.weixin.qq.com/miniprogram/dev/wxcloud/reference-http-api/storage/uploadFile.html)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: ECMAScript 6 简介
|
|||
date: 2020-01-12 15:45:35
|
||||
permalink: /pages/f344d070a1031ef7
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
> 说明:本章内容为博主在原教程基础上添加自己的学习笔记,来源<http://es6.ruanyifeng.com/>,教程版权归原作者所有。
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: let 和 const 命令
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/c1edd70a6b7c7872
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# let 和 const 命令
|
||||
|
||||
|
|
@ -643,4 +643,3 @@ var getGlobal = function () {
|
|||
[ES2020](https://github.com/tc39/proposal-global) 在语言标准的层面,引入`globalThis`作为顶层对象。也就是说,任何环境下,`globalThis`都是存在的,都可以从它拿到顶层对象,指向全局环境下的`this`。
|
||||
|
||||
垫片库[`global-this`](https://github.com/ungap/global-this)模拟了这个提案,可以在所有环境拿到`globalThis`。
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 变量的解构赋值
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/b1ab10a62f7564da
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 变量的解构赋值
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 字符串的扩展
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/ca89eca8adeba5f4
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 字符串的扩展
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 字符串的新增方法
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/a650b4a0ebfc9350
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 字符串的新增方法
|
||||
|
||||
|
|
@ -338,4 +338,3 @@ s.trimEnd() // " abc"
|
|||
## 实例方法:matchAll()
|
||||
|
||||
`matchAll()`方法返回一个正则表达式在当前字符串的所有匹配,详见《正则的扩展》的一章。
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 正则的扩展
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/0473261a6ab0ee8c
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 正则的扩展
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 数值的扩展
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/5dfea9a0f2d1a392
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 数值的扩展
|
||||
|
||||
|
|
@ -967,4 +967,3 @@ BigInt 与字符串混合运算时,会先转为字符串,再进行运算。
|
|||
```javascript
|
||||
'' + 123n // "123"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 函数的扩展
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/8ed309d668b20264
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 函数的扩展
|
||||
|
||||
|
|
@ -1372,4 +1372,3 @@ try {
|
|||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 数组的扩展
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/e34009d60d8bc4b2
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 数组的扩展
|
||||
|
||||
|
|
@ -997,4 +997,3 @@ arr.sort(unstableSorting)
|
|||
常见的排序算法之中,插入排序、合并排序、冒泡排序等都是稳定的,堆排序、快速排序等是不稳定的。不稳定排序的主要缺点是,多重排序时可能会产生问题。假设有一个姓和名的列表,要求按照“姓氏为主要关键字,名字为次要关键字”进行排序。开发者可能会先按名字排序,再按姓氏进行排序。如果排序算法是稳定的,这样就可以达到“先姓氏,后名字”的排序效果。如果是不稳定的,就不行。
|
||||
|
||||
早先的 ECMAScript 没有规定,`Array.prototype.sort()`的默认排序算法是否稳定,留给浏览器自己决定,这导致某些实现是不稳定的。[ES2019](https://github.com/tc39/ecma262/pull/1340) 明确规定,`Array.prototype.sort()`的默认排序算法必须稳定。这个规定已经做到了,现在 JavaScript 各个主要实现的默认排序算法都是稳定的。
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 对象的扩展
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/b5e3e0a0ff6e9c25
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 对象的扩展
|
||||
|
||||
|
|
@ -932,4 +932,3 @@ lhs || (middle ?? rhs);
|
|||
(lhs ?? middle) || rhs;
|
||||
lhs ?? (middle || rhs);
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 对象的新增方法
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/e85e68947502cf90
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 对象的新增方法
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Symbol
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/02c86eb2792f3262
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Symbol
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Set 和 Map 数据结构
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/0c21dae358fca16b
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Set 和 Map 数据结构
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Proxy
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/f56ec2ab97d60483
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Proxy
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Reflect
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/74de3e45e4491e95
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Reflect
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Promise 对象
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/2810ae8985e9bd52
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Promise 对象
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Iterator 和 for-of 循环
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/48df907ad3570f3d
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Iterator 和 for...of 循环
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Generator 函数的语法
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/718b48ed9ce0adce
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Generator 函数的语法
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Generator 函数的异步应用
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/75af7031eb66847b
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Generator 函数的异步应用
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: async 函数
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/3777253e65bac487
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# async 函数
|
||||
|
||||
|
|
@ -867,4 +867,3 @@ console.log("Z");
|
|||
上面代码有三个模块,最后的`z.js`加载`x.js`和`y.js`,打印结果是`X1`、`Y`、`X2`、`Z`。这说明,`z.js`并没有等待`x.js`加载完成,再去加载`y.js`。
|
||||
|
||||
顶层的`await`命令有点像,交出代码的执行权给其他的模块加载,等异步操作完成后,再拿回执行权,继续向下执行。
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Class 的基本语法
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/e831e1593c82bbe0
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Class 的基本语法
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Class 的继承
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/83f8c3a0cd87dd83
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Class 的继承
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ b.m() // 2
|
|||
```javascript
|
||||
class A {
|
||||
constructor() {
|
||||
this.x = 1;
|
||||
this.x = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Module 的语法
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/efe2fb04eb8ac5fb
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Module 的语法
|
||||
|
||||
|
|
@ -810,4 +810,3 @@ async function main() {
|
|||
}
|
||||
main();
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Module 的加载实现
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/a79ca2e64ceae213
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Module 的加载实现
|
||||
|
||||
|
|
@ -840,4 +840,3 @@ $ node
|
|||
> m.even(10)
|
||||
TypeError: even is not a function
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 编程风格
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/984bf549204bb266
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 编程风格
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 读懂 ECMAScript 规格
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/32c35f7651d6e58e
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 读懂 ECMAScript 规格
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 异步遍历器
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/16121351be68691b
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 异步遍历器
|
||||
|
||||
|
|
@ -482,4 +482,3 @@ async function* gen2() {
|
|||
// a
|
||||
// b
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: ArrayBuffer
|
|||
date: 2020-02-09 16:00:29
|
||||
permalink: /pages/a2ba314746bfdbdd
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# ArrayBuffer
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 最新提案
|
|||
date: 2020-02-09 16:00:30
|
||||
permalink: /pages/7188882b8d65af1b
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 最新提案
|
||||
|
||||
|
|
@ -641,4 +641,3 @@ new URL('data.txt', import.meta.url)
|
|||
import.meta.scriptElement.dataset.foo
|
||||
// "abc"
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 装饰器
|
|||
date: 2020-02-09 16:00:30
|
||||
permalink: /pages/e97bc1e5626b082c
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 装饰器
|
||||
|
||||
|
|
@ -811,4 +811,3 @@ class MyClass {}
|
|||
@traits(TExample::as({excludes:['foo', 'bar'], alias: {baz: 'exampleBaz'}}))
|
||||
class MyClass {}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 函数式编程
|
|||
date: 2020-02-09 16:00:30
|
||||
permalink: /pages/1cf50330655efc69
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 函数式编程
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: Mixin
|
|||
date: 2020-02-09 16:00:30
|
||||
permalink: /pages/6a8e2dc558da1b39
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# Mixin
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: SIMD
|
|||
date: 2020-02-09 16:00:30
|
||||
permalink: /pages/8e8f80f69b775a56
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# SIMD
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ title: 参考链接
|
|||
date: 2020-02-09 16:00:30
|
||||
permalink: /pages/ea6f3b870f6dab69
|
||||
author: 阮一峰
|
||||
categories:
|
||||
categories:
|
||||
- 《ES6 教程》笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- ES6
|
||||
---
|
||||
# 参考链接
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ permalink: /pages/8292d8/
|
|||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
- Git
|
||||
---
|
||||
# 常用Git命令清单
|
||||
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ permalink: /pages/c10281/
|
|||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
- Git
|
||||
---
|
||||
# rebase分支合并
|
||||
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@
|
|||
title: Git命令思维导图
|
||||
date: 2020-11-18 17:46:22
|
||||
permalink: /pages/4cbc21/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||

|
||||

|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git基础与命令
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/635088/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git基础与命令
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ git help
|
|||
# 获取特定命令的详细版帮助手册 (两个命令是等价的)
|
||||
git help <某个命令>
|
||||
git <某个命令> --help # 两个横杠
|
||||
|
||||
|
||||
# 获取特定命令的简明版帮助手册
|
||||
git <某个命令> -h # 一个横杠
|
||||
```
|
||||
|
|
@ -528,6 +528,3 @@ Date: Tue Aug 26 19:48:51 2008 +0800
|
|||
```sh
|
||||
$ git config --global alias.visual '!gitk'
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git工具-重写历史
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/1832fe/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git 工具 - 重写历史
|
||||
|
||||
|
|
@ -293,4 +293,4 @@ $ git filter-branch --commit-filter '
|
|||
fi' HEAD
|
||||
```
|
||||
|
||||
这会遍历并重写每一个提交来包含你的新邮箱地址。 因为提交包含了它们父提交的 SHA-1 校验和,这个命令会修改你的历史中的每一个提交的 SHA-1 校验和, 而不仅仅只是那些匹配邮箱地址的提交。
|
||||
这会遍历并重写每一个提交来包含你的新邮箱地址。 因为提交包含了它们父提交的 SHA-1 校验和,这个命令会修改你的历史中的每一个提交的 SHA-1 校验和, 而不仅仅只是那些匹配邮箱地址的提交。
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git工具-重置揭密
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/d9e9c6/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git 工具 - 重置揭密
|
||||
|
||||
|
|
@ -251,4 +251,4 @@ $ tree
|
|||
| `checkout <commit>` | HEAD | YES | YES | YES |
|
||||
| **File Level** | | | | |
|
||||
| `reset [commit] <paths>` | NO | YES | NO | YES |
|
||||
| `checkout [commit] <paths>` | NO | YES | YES | **NO** |
|
||||
| `checkout [commit] <paths>` | NO | YES | YES | **NO** |
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git分支-分支原理
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/4bef1a/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git分支-分支原理
|
||||
|
||||
|
|
@ -176,5 +176,5 @@ $ git log --oneline --decorate --graph --all
|
|||
通常我们会在创建一个新分支后立即切换过去,可以使用如下命令:
|
||||
|
||||
```sh
|
||||
git checkout -b <newbranchname>
|
||||
git checkout -b <newbranchname>
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git分支的新建与合并-分支操作
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/ea5a8c/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git分支的新建与合并-分支操作
|
||||
|
||||
|
|
@ -52,7 +52,7 @@ $ git checkout master
|
|||
$ git checkout -b hotfix
|
||||
|
||||
# 中间过程在hotfix上修改了代码并提交
|
||||
$ echo 'test' > ./hotfix.txt
|
||||
$ echo 'test' > ./hotfix.txt
|
||||
$ git add .
|
||||
$ git commit -m 'fixed'
|
||||
```
|
||||
|
|
@ -128,4 +128,3 @@ Automatic merge failed; fix conflicts and then commit the result.
|
|||
你需要**手动解决冲突**,解决了所有文件里的冲突之后,对每个文件**使用 `git add` 命令**来将其标记为冲突已解决。 **一旦暂存这些原本有冲突的文件,Git 就会将它们标记为冲突已解决**。
|
||||
|
||||
如果你对结果感到满意,并且确定之前有冲突的的文件都已经暂存了,这时你可以输入 `git commit` 来完成合并提交。
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git分支管理-查看分支
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/a399b3/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git分支管理-查看分支
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ error: The branch 'testing' is not fully merged.
|
|||
If you are sure you want to delete it, run 'git branch -D testing'.
|
||||
```
|
||||
|
||||
强制删除未合并的分支:
|
||||
强制删除未合并的分支:
|
||||
|
||||
```sh
|
||||
$ git branch -D testing
|
||||
|
|
@ -78,4 +78,4 @@ $ git branch -D testing
|
|||
$ git branch --no-merged testing
|
||||
topicA
|
||||
featureB
|
||||
```
|
||||
```
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git分支开发工作流
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/49ee30/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git分支开发工作流
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ tags:
|
|||
|
||||
### 主题分支 (短期分支)
|
||||
|
||||
**主题分支对任何规模的项目都适用**。 主题分支是一种**短期分支**,它被**用来实现单一特性或其相关工作**。
|
||||
**主题分支对任何规模的项目都适用**。 主题分支是一种**短期分支**,它被**用来实现单一特性或其相关工作**。
|
||||
|
||||
你已经在上一节中你创建的 `iss53` 和 `hotfix` 主题分支中看到过这种用法。 你在上一节用到的主题分支(`iss53` 和 `hotfix` 分支)中提交了一些更新,并且在它们合并入主干分支之后,你又删除了它们。 这项技术能使你快速并且完整地进行上下文切换(context-switch)——因为你的工作被分散到不同的流水线中,在不同的流水线中**每个分支都仅与其目标特性相关**,因此,**在做代码审查之类的工作的时候就能更加容易地看出你做了哪些改动**。 你可以把做出的改动在主题分支中保留几分钟、几天甚至几个月,等它们成熟之后再合并,而不用在乎它们建立的顺序或工作进度。
|
||||
|
||||
|
|
@ -53,4 +53,4 @@ tags:
|
|||
|
||||
我们将会在 [分布式 Git](https://git-scm.com/book/zh/v2/ch00/ch05-distributed-git) 中向你揭示更多有关分支工作流的细节, 因此,请确保你阅读完那个章节之后,再来决定你的下个项目要使用什么样的分支策略(branching scheme)。
|
||||
|
||||
请牢记,当你做这么多操作的时候,这些分支全部都存于本地。 当你新建和合并分支的时候,所有这一切都只发生在你本地的 Git 版本库中 —— 没有与服务器发生交互。
|
||||
请牢记,当你做这么多操作的时候,这些分支全部都存于本地。 当你新建和合并分支的时候,所有这一切都只发生在你本地的 Git 版本库中 —— 没有与服务器发生交互。
|
||||
|
|
|
|||
|
|
@ -2,14 +2,14 @@
|
|||
title: Git分支-远程分支
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/574d62/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git分支-远程分支
|
||||
|
||||
**远程引用是对远程仓库的引用(指针)**,包括分支、标签等等。
|
||||
**远程引用是对远程仓库的引用(指针)**,包括分支、标签等等。
|
||||
|
||||
> 远程分支本质上也是一个指针,指向远程地址
|
||||
|
||||
|
|
@ -83,7 +83,7 @@ To https://github.com/schacon/simplegit
|
|||
* [new branch] serverfix -> serverfix
|
||||
```
|
||||
|
||||
这里有些工作被简化了。 **Git 自动将 `serverfix` 分支名字展开为 `refs/heads/serverfix:refs/heads/serverfix`,** 那意味着,“推送本地的 `serverfix` 分支来更新远程仓库上的 `serverfix` 分支。” 我们将会详细学习 [Git 内部原理](https://git-scm.com/book/zh/v2/ch00/ch10-git-internals) 的 `refs/heads/` 部分, 但是现在可以先把它放在儿。你也可以运行 `git push origin serverfix:serverfix`, 它会做同样的事——也就是说“**推送本地的 `serverfix` 分支,将其作为远程仓库的 `serverfix` 分支**” 可以通过这种格式来推送本地分支到一个命名不相同的远程分支。
|
||||
这里有些工作被简化了。 **Git 自动将 `serverfix` 分支名字展开为 `refs/heads/serverfix:refs/heads/serverfix`,** 那意味着,“推送本地的 `serverfix` 分支来更新远程仓库上的 `serverfix` 分支。” 我们将会详细学习 [Git 内部原理](https://git-scm.com/book/zh/v2/ch00/ch10-git-internals) 的 `refs/heads/` 部分, 但是现在可以先把它放在儿。你也可以运行 `git push origin serverfix:serverfix`, 它会做同样的事——也就是说“**推送本地的 `serverfix` 分支,将其作为远程仓库的 `serverfix` 分支**” 可以通过这种格式来推送本地分支到一个命名不相同的远程分支。
|
||||
|
||||
#### 重命名远程仓库上的分支名
|
||||
|
||||
|
|
@ -196,4 +196,4 @@ To https://github.com/schacon/simplegit
|
|||
- [deleted] serverfix
|
||||
```
|
||||
|
||||
基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。
|
||||
基本上这个命令做的只是从服务器上移除这个指针。 Git 服务器通常会保留数据一段时间直到垃圾回收运行,所以如果不小心删除掉了,通常是很容易恢复的。
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git分支-变基
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/3a3247/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git分支-变基
|
||||
|
||||
|
|
@ -276,4 +276,4 @@ $ git branch -d server
|
|||
|
||||
现在,让我们回到之前的问题上来,到底合并还是变基好?希望你能明白,这并没有一个简单的答案。 Git 是一个非常强大的工具,它允许你对提交历史做许多事情,但每个团队、每个项目对此的需求并不相同。 既然你已经分别学习了两者的用法,相信你能够根据实际情况作出明智的选择。
|
||||
|
||||
**总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。**
|
||||
**总的原则是,只对尚未推送或分享给别人的本地修改执行变基操作清理历史, 从不对已推送至别处的提交执行变基操作,这样,你才能享受到两种方式带来的便利。**
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git工具-查看修订版本
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/c984d1/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git工具-查看修订版本
|
||||
|
||||
|
|
@ -309,4 +309,4 @@ $ git log --left-right master...experiment
|
|||
> C
|
||||
```
|
||||
|
||||
有了这些工具,你就可以十分方便地查看你 Git 仓库中的提交。
|
||||
有了这些工具,你就可以十分方便地查看你 Git 仓库中的提交。
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
title: Git工具-交互式暂存
|
||||
date: 2020-11-18 17:43:57
|
||||
permalink: /pages/76d859/
|
||||
categories:
|
||||
categories:
|
||||
- 《Git》学习笔记
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- Git
|
||||
---
|
||||
# Git工具-交互式暂存
|
||||
|
||||
|
|
@ -181,4 +181,4 @@ What now> 1
|
|||
|
||||
也可以不必在交互式添加模式中做部分文件暂存——可以在命令行中使用 `git add -p` 或 `git add --patch` 来启动同样的脚本。
|
||||
|
||||
更进一步地,可以使用 `git reset --patch` 命令的补丁模式来部分重置文件, 通过 `git checkout --patch` 命令来部分检出文件与 `git stash save --patch` 命令来部分暂存文件。 我们将会在接触这些命令的高级使用方法时了解更多详细信息。
|
||||
更进一步地,可以使用 `git reset --patch` 命令的补丁模式来部分重置文件, 通过 `git checkout --patch` 命令来部分检出文件与 `git stash save --patch` 命令来部分暂存文件。 我们将会在接触这些命令的高级使用方法时了解更多详细信息。
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
title: 基础
|
||||
date: 2020-01-12 11:49:16
|
||||
permalink: /pages/0796ba76b4b55368
|
||||
categories:
|
||||
categories:
|
||||
- 《JavaScript教程》笔记
|
||||
tags:
|
||||
- null
|
||||
author:
|
||||
tags:
|
||||
- JavaScript
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -36,7 +36,7 @@ author:
|
|||
|
||||
* 可以读取函数内部变量
|
||||
* 让这些变量始终保持在内存中,即闭包可以使得它诞生的环境一直存在。
|
||||
* 封装对象的私有属性和私有方法
|
||||
* 封装对象的私有属性和私有方法
|
||||
|
||||
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ prototype原型对象都有一个constructor属性,默认指向prototype对象
|
|||
|
||||
### 1、强制(手动)转换
|
||||
|
||||
强制转换主要指使用`Number()`、`String()`和`Boolean()`三个函数,手动将各种类型的值,分别转换成**数字、字符串、布尔值**。
|
||||
强制转换主要指使用`Number()`、`String()`和`Boolean()`三个函数,手动将各种类型的值,分别转换成**数字、字符串、布尔值**。
|
||||
|
||||
#### Number()
|
||||
|
||||
|
|
@ -174,7 +174,7 @@ Boolean(' ') // true // 注意字符串内有个空格
|
|||
123 + 'abc' // "123abc"
|
||||
```
|
||||
|
||||
第二种情况,**对非布尔值类型的数据求布尔值**。
|
||||
第二种情况,**对非布尔值类型的数据求布尔值**。
|
||||
|
||||
```js
|
||||
if ('abc') {
|
||||
|
|
@ -182,7 +182,7 @@ if ('abc') {
|
|||
} // "hello"
|
||||
```
|
||||
|
||||
第三种情况,**对非数值类型的值使用一元运算符(即`+`和`-`)**。
|
||||
第三种情况,**对非数值类型的值使用一元运算符(即`+`和`-`)**。
|
||||
|
||||
```js
|
||||
+ {foo: 'bar'} // NaN
|
||||
|
|
@ -254,7 +254,7 @@ JavaScript 遇到预期为字符串的地方,就会将非字符串的值自动
|
|||
'5' + null // "5null"
|
||||
```
|
||||
|
||||
#####
|
||||
#####
|
||||
|
||||
这种自动转换不注意的话很容易出错。
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ if (err.name) {
|
|||
}
|
||||
```
|
||||
|
||||
`stack`属性用来查看错误发生时的堆栈。
|
||||
`stack`属性用来查看错误发生时的堆栈。
|
||||
|
||||
```js
|
||||
function throwit() {
|
||||
|
|
@ -371,20 +371,20 @@ catchit()
|
|||
|
||||
// 堆栈信息说明
|
||||
// Error 错误
|
||||
// at throwit 在throwit方法 (~/examples/throwcatch.js:9:11) 文件名:第几行:第几个字符
|
||||
// at throwit 在throwit方法 (~/examples/throwcatch.js:9:11) 文件名:第几行:第几个字符
|
||||
// at catchit 在catchit方法 (~/examples/throwcatch.js:3:9) 文件名:第几行:第几个字符
|
||||
// at repl:1:5 // 函数的运行环境
|
||||
```
|
||||
|
||||
上面代码中,错误堆栈的最内层是`throwit`函数,然后是`catchit`函数,最后是函数的运行环境。
|
||||
上面代码中,错误堆栈的最内层是`throwit`函数,然后是`catchit`函数,最后是函数的运行环境。
|
||||
|
||||
### 2、原生错误类型
|
||||
|
||||
`Error`实例对象是最一般的错误类型,在它的基础上,JavaScript 还定义了其他6种错误对象。也就是说,存在`Error`的6个派生对象。
|
||||
`Error`实例对象是最一般的错误类型,在它的基础上,JavaScript 还定义了其他6种错误对象。也就是说,存在`Error`的6个派生对象。
|
||||
|
||||
#### SyntaxError 对象(语法错误)
|
||||
|
||||
`SyntaxError`对象是解析代码时发生的**语法错误**。
|
||||
`SyntaxError`对象是解析代码时发生的**语法错误**。
|
||||
|
||||
```js
|
||||
// 变量名错误
|
||||
|
|
@ -404,7 +404,7 @@ console.log 'hello');
|
|||
|
||||
#### ReferenceError 对象(引用错误)
|
||||
|
||||
`ReferenceError`对象是**引用一个不存在的变量时发生的错误**。
|
||||
`ReferenceError`对象是**引用一个不存在的变量时发生的错误**。
|
||||
|
||||
```js
|
||||
// 使用一个不存在的变量
|
||||
|
|
@ -433,7 +433,7 @@ this = 1
|
|||
|
||||
#### RangeError 对象(范围错误)
|
||||
|
||||
`RangeError`对象是一个值**超出有效范围时发生的错误**。主要有几种情况,一是数组长度为负数,二是`Number`对象的方法参数超出范围,以及函数堆栈超过最大值。
|
||||
`RangeError`对象是一个值**超出有效范围时发生的错误**。主要有几种情况,一是数组长度为负数,二是`Number`对象的方法参数超出范围,以及函数堆栈超过最大值。
|
||||
|
||||
```js
|
||||
// 数组长度不得为负数
|
||||
|
|
@ -446,7 +446,7 @@ new Array(-1)
|
|||
|
||||
#### TypeError 对象(类型错误)
|
||||
|
||||
`TypeError`对象是**变量或参数不是预期类型时发生的错误**。比如,对字符串、布尔值、数值等原始类型的值使用`new`命令,就会抛出这种错误,因为`new`命令的参数应该是一个构造函数。
|
||||
`TypeError`对象是**变量或参数不是预期类型时发生的错误**。比如,对字符串、布尔值、数值等原始类型的值使用`new`命令,就会抛出这种错误,因为`new`命令的参数应该是一个构造函数。
|
||||
|
||||
```js
|
||||
new 123
|
||||
|
|
@ -498,7 +498,7 @@ err3.message // "出错了,变量类型无效!"
|
|||
|
||||
### 3、自定义错误
|
||||
|
||||
除了 JavaScript 原生提供的七种错误对象,还可以定义自己的错误对象。
|
||||
除了 JavaScript 原生提供的七种错误对象,还可以定义自己的错误对象。
|
||||
|
||||
```js
|
||||
function UserError(message) {
|
||||
|
|
@ -519,7 +519,7 @@ new UserError('这是自定义的错误!');
|
|||
|
||||
### 4、throw 语句 (中断程序并抛出错误)
|
||||
|
||||
`throw`语句的作用是**手动中断程序执行,抛出一个错误**。
|
||||
`throw`语句的作用是**手动中断程序执行,抛出一个错误**。
|
||||
|
||||
```js
|
||||
var x = 0;
|
||||
|
|
@ -529,7 +529,7 @@ if (x <= 0) {
|
|||
// Uncaught Error: x 必须为正数
|
||||
```
|
||||
|
||||
上面代码中,如果变量`x`小于等于`0`,就手动抛出一个错误,告诉用户`x`的值不正确,整个程序就会在这里中断执行。可以看到,`throw`抛出的错误就是它的参数,这里是一个`Error`实例。
|
||||
上面代码中,如果变量`x`小于等于`0`,就手动抛出一个错误,告诉用户`x`的值不正确,整个程序就会在这里中断执行。可以看到,`throw`抛出的错误就是它的参数,这里是一个`Error`实例。
|
||||
|
||||
```js
|
||||
function UserError(message) {
|
||||
|
|
@ -541,7 +541,7 @@ throw new UserError('出错了!');
|
|||
// Uncaught UserError {message: "出错了!", name: "UserError"}
|
||||
```
|
||||
|
||||
上面代码中,`throw`抛出的是一个`UserError`实例。
|
||||
上面代码中,`throw`抛出的是一个`UserError`实例。
|
||||
|
||||
实际上,`throw`可以抛出任何类型的值。也就是说,它的参数可以是任何值。
|
||||
|
||||
|
|
@ -567,11 +567,11 @@ throw {
|
|||
// Uncaught {toString: ƒ}
|
||||
```
|
||||
|
||||
对于 JavaScript 引擎来说,**遇到`throw`语句,程序就中止了**。引擎会接收到`throw`抛出的信息,可能是一个错误实例,也可能是其他类型的值。
|
||||
对于 JavaScript 引擎来说,**遇到`throw`语句,程序就中止了**。引擎会接收到`throw`抛出的信息,可能是一个错误实例,也可能是其他类型的值。
|
||||
|
||||
### 5、try...catch 结构(捕获错误,对错误进行处理,不中断)
|
||||
|
||||
一旦发生错误,程序就中止执行了。JavaScript 提供了`try...catch`结构,**允许对错误进行处理**,选择是否往下执行。
|
||||
一旦发生错误,程序就中止执行了。JavaScript 提供了`try...catch`结构,**允许对错误进行处理**,选择是否往下执行。
|
||||
|
||||
```js
|
||||
try {
|
||||
|
|
@ -652,7 +652,7 @@ try {
|
|||
|
||||
### 6、finally 代码块(在try..catch最后,必执行的)
|
||||
|
||||
`try...catch`结构允许在最后添加一个`finally`代码块,表示**不管是否出现错误,都必需在最后运行的语句**。
|
||||
`try...catch`结构允许在最后添加一个`finally`代码块,表示**不管是否出现错误,都必需在最后运行的语句**。
|
||||
|
||||
```js
|
||||
function cleansUp() {
|
||||
|
|
@ -667,7 +667,7 @@ function cleansUp() {
|
|||
|
||||
cleansUp()
|
||||
// 完成清理工作
|
||||
// Uncaught Error: 出错了……
|
||||
// Uncaught Error: 出错了……
|
||||
// at cleansUp (<anonymous>:3:11)
|
||||
// at <anonymous>:10:1
|
||||
|
||||
|
|
@ -675,7 +675,7 @@ cleansUp()
|
|||
// 如果有catch语句则会执行catch内的代码块,而不会打印错误信息。且不会中断代码。
|
||||
```
|
||||
|
||||
上面代码中,由于没有`catch`语句块,一旦发生错误,代码就会中断执行。中断执行之前,会先执行`finally`代码块,然后再向用户提示报错信息。
|
||||
上面代码中,由于没有`catch`语句块,一旦发生错误,代码就会中断执行。中断执行之前,会先执行`finally`代码块,然后再向用户提示报错信息。
|
||||
|
||||
```js
|
||||
function idle(x) {
|
||||
|
|
@ -833,4 +833,4 @@ console.timeEnd('Array initialize');
|
|||
|
||||
## 文档
|
||||
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
title: 内置对象
|
||||
date: 2020-01-12 11:49:16
|
||||
permalink: /pages/74d2ab3fbfeaaa68
|
||||
categories:
|
||||
categories:
|
||||
- 《JavaScript教程》笔记
|
||||
tags:
|
||||
- null
|
||||
author:
|
||||
tags:
|
||||
- JavaScript
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -123,7 +123,7 @@ obj === fn // true
|
|||
|
||||
利用这一点,可以写一个**判断变量是否为对象**的函数。
|
||||
|
||||
```
|
||||
```
|
||||
function isObject(value){
|
||||
return value === Object(value)
|
||||
}
|
||||
|
|
@ -611,14 +611,14 @@ Object.getOwnPropertyNames(Object.prototype)
|
|||
/*[
|
||||
"constructor", // 构造函数
|
||||
"__defineGetter__",
|
||||
"__defineSetter__",
|
||||
"__defineSetter__",
|
||||
"hasOwnProperty", // 检测属性名
|
||||
"__lookupGetter__",
|
||||
"__lookupSetter__",
|
||||
"isPrototypeOf",
|
||||
"propertyIsEnumerable",
|
||||
"__lookupGetter__",
|
||||
"__lookupSetter__",
|
||||
"isPrototypeOf",
|
||||
"propertyIsEnumerable",
|
||||
"toString", // 返回类型字符串
|
||||
"valueOf",
|
||||
"valueOf",
|
||||
"__proto__", // 原型链
|
||||
"toLocaleString"
|
||||
]
|
||||
|
|
@ -1547,7 +1547,7 @@ var queue = []
|
|||
queue.push('1')
|
||||
queue.push('2')
|
||||
queue.push('3')
|
||||
queue.shift()
|
||||
queue.shift()
|
||||
queue // ['2','3']
|
||||
```
|
||||
|
||||
|
|
@ -2111,7 +2111,7 @@ arr.every(fn,obj) // true
|
|||
// 最终结果 15
|
||||
```
|
||||
|
||||
上面代码中,`reduce`方法求出数组所有成员的和。第一次执行,`a`是数组的第一个成员`1`,`b`是数组的第二个成员`2`。第二次执行,`a`为上一轮的返回值`3`,`b`为第三个成员`3`。第三次执行,`a`为上一轮的返回值`6`,`b`为第四个成员`4`。第四次执行,`a`为上一轮返回值`10`,`b`为第五个成员`5`。至此所有成员遍历完成,整个方法的返回值就是最后一轮的返回值`15`。
|
||||
上面代码中,`reduce`方法求出数组所有成员的和。第一次执行,`a`是数组的第一个成员`1`,`b`是数组的第二个成员`2`。第二次执行,`a`为上一轮的返回值`3`,`b`为第三个成员`3`。第三次执行,`a`为上一轮的返回值`6`,`b`为第四个成员`4`。第四次执行,`a`为上一轮返回值`10`,`b`为第五个成员`5`。至此所有成员遍历完成,整个方法的返回值就是最后一轮的返回值`15`。
|
||||
|
||||
```js
|
||||
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
|
||||
|
|
@ -2131,7 +2131,7 @@ arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue]
|
|||
|
||||
|
||||
|
||||
如果要对累积变量指定初值,可以把它放在`reduce`方法和`reduceRight`方法的第二个参数。
|
||||
如果要对累积变量指定初值,可以把它放在`reduce`方法和`reduceRight`方法的第二个参数。
|
||||
|
||||
```js
|
||||
[1, 2, 3, 4, 5].reduce(function (a, b) {
|
||||
|
|
@ -2210,12 +2210,12 @@ function groupBy(objectArray, property) {
|
|||
|
||||
var groupedPeople = groupBy(people, 'age');
|
||||
// groupedPeople is:
|
||||
// {
|
||||
// {
|
||||
// 20: [
|
||||
// { name: 'Max', age: 20 },
|
||||
// { name: 'Max', age: 20 },
|
||||
// { name: 'Jane', age: 20 }
|
||||
// ],
|
||||
// 21: [{ name: 'Alice', age: 21 }]
|
||||
// ],
|
||||
// 21: [{ name: 'Alice', age: 21 }]
|
||||
// }
|
||||
```
|
||||
|
||||
|
|
@ -2223,7 +2223,7 @@ var groupedPeople = groupBy(people, 'age');
|
|||
|
||||
### indexOf() 搜索成员第一个出现的位置,lastIndexOf() 搜索成员最后出现的位置
|
||||
|
||||
`indexOf`方法返回**给定元素在数组中第一次出现的位置**,如果**没有则返回`-1`**。
|
||||
`indexOf`方法返回**给定元素在数组中第一次出现的位置**,如果**没有则返回`-1`**。
|
||||
|
||||
|
||||
|
||||
|
|
@ -2241,7 +2241,7 @@ a.indexOf(6) // -1 6在数组a中没有出现,返回-1
|
|||
|
||||
|
||||
|
||||
`indexOf`方法还可以接受第二个参数,表示搜索的开始位置。
|
||||
`indexOf`方法还可以接受第二个参数,表示搜索的开始位置。
|
||||
|
||||
```js
|
||||
['a', 'b', 'c'].indexOf('a', 1) // -1 从1位置开始搜索a,没有搜索到
|
||||
|
|
@ -2259,12 +2259,12 @@ a.indexOf(6) // -1 6在数组a中没有出现,返回-1
|
|||
arr.lastIndexOf(searchElement[, fromIndex = arr.length - 1])
|
||||
```
|
||||
|
||||
`lastIndexOf`方法返回**给定元素在数组中最后一次出现的位置**,如果没有则返回`-1`。
|
||||
`lastIndexOf`方法返回**给定元素在数组中最后一次出现的位置**,如果没有则返回`-1`。
|
||||
|
||||
```js
|
||||
var a = [2,3,4,2]
|
||||
a.lastIndexOf(2) //3 2在数组a中最后一次出现的位置为3
|
||||
a.lastIndexOf(5) //-1
|
||||
a.lastIndexOf(5) //-1
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -2313,7 +2313,7 @@ users
|
|||
|
||||
对象是JavaScript语言中最主要的数据类型,三种原始类型的值——数字、字符串、布尔值 在一定条件下,也会自动转为对象,也就是原始类型的**包装对象**(wrapper)
|
||||
|
||||
所谓“包装对象”,**指的是与数字、字符串、布尔值分别相对应的`Number`、`String`、`Boolean`三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象**。
|
||||
所谓“包装对象”,**指的是与数字、字符串、布尔值分别相对应的`Number`、`String`、`Boolean`三个原生对象。这三个原生对象可以把原始类型的值变成(包装成)对象**。
|
||||
|
||||
|
||||
|
||||
|
|
@ -2337,7 +2337,7 @@ v3 === true // false
|
|||
|
||||
|
||||
|
||||
`Number`、`String`和`Boolean`这三个原生对象,如果不作为构造函数调用(即调用时不加`new`),而是作为普通函数调用,常常用于将任意类型的值转为数值、字符串和布尔值。
|
||||
`Number`、`String`和`Boolean`这三个原生对象,如果不作为构造函数调用(即调用时不加`new`),而是作为普通函数调用,常常用于将任意类型的值转为数值、字符串和布尔值。
|
||||
|
||||
```js
|
||||
// 字符串转为数值
|
||||
|
|
@ -2352,19 +2352,19 @@ Boolean(123) // true
|
|||
|
||||
上面这种**数据类型的转换**,详见《数据类型转换》一节。
|
||||
|
||||
总结一下,这三个对象作为构造函数使用(带有`new`)时,可以将原始类型的值转为对象;作为普通函数使用时(不带有`new`),可以将任意类型的值,转为原始类型的值。
|
||||
总结一下,这三个对象作为构造函数使用(带有`new`)时,可以将原始类型的值转为对象;作为普通函数使用时(不带有`new`),可以将任意类型的值,转为原始类型的值。
|
||||
|
||||
|
||||
|
||||
## 2、实例方法
|
||||
|
||||
三种包装对象各自提供了许多实例方法,详见后文。这里介绍两种它们共同具有、从`Object`对象**继承的方法**:`valueOf()`和`toString()`。
|
||||
三种包装对象各自提供了许多实例方法,详见后文。这里介绍两种它们共同具有、从`Object`对象**继承的方法**:`valueOf()`和`toString()`。
|
||||
|
||||
|
||||
|
||||
### 2.1 valueOf()
|
||||
|
||||
`valueOf()`方法返回包装对象实例对应的原始类型的值。
|
||||
`valueOf()`方法返回包装对象实例对应的原始类型的值。
|
||||
|
||||
```js
|
||||
new Number(123).valueOf() // 123
|
||||
|
|
@ -2410,9 +2410,9 @@ var strObj = new String(str)
|
|||
strObj.length // 3
|
||||
```
|
||||
|
||||
上面代码中,字符串`abc`的包装对象提供了多个属性,`length`只是其中之一。
|
||||
上面代码中,字符串`abc`的包装对象提供了多个属性,`length`只是其中之一。
|
||||
|
||||
自动转换生成的包装对象是只读的,无法修改。所以,字符串无法添加新属性。
|
||||
自动转换生成的包装对象是只读的,无法修改。所以,字符串无法添加新属性。
|
||||
|
||||
```js
|
||||
var s = 'Hello World';
|
||||
|
|
@ -2420,9 +2420,9 @@ s.x = 123;
|
|||
s.x // undefined
|
||||
```
|
||||
|
||||
上面代码为字符串`s`添加了一个`x`属性,结果无效,总是返回`undefined`。
|
||||
上面代码为字符串`s`添加了一个`x`属性,结果无效,总是返回`undefined`。
|
||||
|
||||
另一方面,调用结束后,包装对象实例会自动销毁。这意味着,下一次调用字符串的属性时,实际是调用一个新生成的对象,而不是上一次调用时生成的那个对象,所以取不到赋值在上一个对象的属性。如果要为字符串添加属性,只有在它的原型对象`String.prototype`上定义(参见《面向对象编程》章节)。
|
||||
另一方面,调用结束后,包装对象实例会自动销毁。这意味着,下一次调用字符串的属性时,实际是调用一个新生成的对象,而不是上一次调用时生成的那个对象,所以取不到赋值在上一个对象的属性。如果要为字符串添加属性,只有在它的原型对象`String.prototype`上定义(参见《面向对象编程》章节)。
|
||||
|
||||
|
||||
|
||||
|
|
@ -2447,7 +2447,7 @@ Number.prototype.double = function () {
|
|||
(123).double() // 246 // 不加括号时点运算符会被解释成小数点
|
||||
```
|
||||
|
||||
上面代码在`String`和`Number`这两个对象的原型上面,分别自定义了一个方法,从而可以在所有实例对象上调用。注意,最后一张的`123`外面必须要加上圆括号,否则后面的点运算符(`.`)会被解释成小数点。
|
||||
上面代码在`String`和`Number`这两个对象的原型上面,分别自定义了一个方法,从而可以在所有实例对象上调用。注意,最后一张的`123`外面必须要加上圆括号,否则后面的点运算符(`.`)会被解释成小数点。
|
||||
|
||||
|
||||
|
||||
|
|
@ -2455,7 +2455,7 @@ Number.prototype.double = function () {
|
|||
|
||||
## 1、概述
|
||||
|
||||
`Boolean`对象是 JavaScript 的三个包装对象之一。作为构造函数,它主要用于生成布尔值的包装对象实例。
|
||||
`Boolean`对象是 JavaScript 的三个包装对象之一。作为构造函数,它主要用于生成布尔值的包装对象实例。
|
||||
|
||||
```js
|
||||
var b = new Boolean(true)
|
||||
|
|
@ -2463,9 +2463,9 @@ typeof b // object
|
|||
b.valueOf() // true
|
||||
```
|
||||
|
||||
上面代码的变量`b`是一个`Boolean`对象的实例,它的类型是对象,值为布尔值`true`。
|
||||
上面代码的变量`b`是一个`Boolean`对象的实例,它的类型是对象,值为布尔值`true`。
|
||||
|
||||
注意,`false`对应的包装对象实例,布尔运算结果也是`true`。
|
||||
注意,`false`对应的包装对象实例,布尔运算结果也是`true`。
|
||||
|
||||
```js
|
||||
if (new Boolean(false)) { // 返回的是一个对象,所有对象对应的布尔值都是true
|
||||
|
|
@ -2559,9 +2559,9 @@ typeof n // object
|
|||
n.valueOf() // 1
|
||||
```
|
||||
|
||||
上面代码中,`Number`对象作为构造函数使用,返回一个值为`1`的对象。
|
||||
上面代码中,`Number`对象作为构造函数使用,返回一个值为`1`的对象。
|
||||
|
||||
作为工具函数时,它可以将任何类型的值转为数值。
|
||||
作为工具函数时,它可以将任何类型的值转为数值。
|
||||
|
||||
```js
|
||||
Number(true) // 1
|
||||
|
|
@ -2577,13 +2577,13 @@ Number(undefined) // NaN
|
|||
Number('123')// 123
|
||||
```
|
||||
|
||||
上面代码将布尔值`true`转为数值`1`。`Number`作为工具函数的用法,详见《数据类型转换》一章。
|
||||
上面代码将布尔值`true`转为数值`1`。`Number`作为工具函数的用法,详见《数据类型转换》一章。
|
||||
|
||||
|
||||
|
||||
## 2、静态属性
|
||||
|
||||
`Number`对象拥有以下一些静态属性(即直接定义在`Number`对象上的属性,而不是定义在实例上的属性)。
|
||||
`Number`对象拥有以下一些静态属性(即直接定义在`Number`对象上的属性,而不是定义在实例上的属性)。
|
||||
|
||||
- `Number.POSITIVE_INFINITY`:正的无限,指向`Infinity`。
|
||||
- `Number.NEGATIVE_INFINITY`:负的无限,指向`-Infinity`。
|
||||
|
|
@ -2614,7 +2614,7 @@ Number.MIN_SAFE_INTEGER // -9007199254740991
|
|||
|
||||
## 3、实例方法
|
||||
|
||||
`Number`对象有**4个实例方法**,都跟**将数值转换成指定格式有关**。
|
||||
`Number`对象有**4个实例方法**,都跟**将数值转换成指定格式有关**。
|
||||
|
||||
### 3.1 Number.prototype.toString() 可转成多种进制字符串
|
||||
|
||||
|
|
@ -2884,7 +2884,7 @@ String(['1','2']) // '1,2'
|
|||
|
||||
|
||||
|
||||
## 2、静态方法
|
||||
## 2、静态方法
|
||||
|
||||
### String.fromCharCode()
|
||||
|
||||
|
|
@ -3186,10 +3186,10 @@ one + two + three // "33"
|
|||
`match`方法**用于确定原字符串是否匹配某个子字符串,返回一个数组,成员为匹配的第一个字符串**。如果没有找到匹配,则返回`null`。
|
||||
|
||||
```js
|
||||
'cat, bat, sat, fat'.match('at') // ["at"]
|
||||
'cat, bat, sat, fat'.match('at') // ["at"]
|
||||
// ["at", index: 1, input: "cat, bat, sat, fat", groups: undefined]
|
||||
|
||||
'catbatsatbat'.match('bat') // ["bat"]
|
||||
'catbatsatbat'.match('bat') // ["bat"]
|
||||
//["bat", index: 3, input: "catbatsatbat", groups: undefined]
|
||||
// index属性为bat首次出现的索引
|
||||
|
||||
|
|
@ -3320,7 +3320,7 @@ str.replace('c','b') // 'aaa' 匹配不到返回原字符串
|
|||
|
||||
## 八、Math对象
|
||||
|
||||
`Math`是 JavaScript 的原生对象,提供各种**数学**功能。该对象**不是构造函数,不能生成实例**,所有的属性和方法都必须在`Math`对象上调用。
|
||||
`Math`是 JavaScript 的原生对象,提供各种**数学**功能。该对象**不是构造函数,不能生成实例**,所有的属性和方法都必须在`Math`对象上调用。
|
||||
|
||||
## 1、静态属性
|
||||
|
||||
|
|
@ -3566,7 +3566,7 @@ Math.atan(1) // 0.7853981633974483
|
|||
|
||||
## 九、Date对象
|
||||
|
||||
`Date`对象是 JavaScript 原生的时间库。它以国际标准时间(UTC)1970年1月1日00:00:00作为时间的零点,可以表示的时间范围是前后各1亿天(单位为毫秒)。
|
||||
`Date`对象是 JavaScript 原生的时间库。它以国际标准时间(UTC)1970年1月1日00:00:00作为时间的零点,可以表示的时间范围是前后各1亿天(单位为毫秒)。
|
||||
|
||||
## 1、普通函数的用法
|
||||
|
||||
|
|
@ -3781,7 +3781,7 @@ Date.UTC(2011, 0, 1, 2, 3, 4, 567)
|
|||
|
||||
|
||||
|
||||
## 5、实例方法
|
||||
## 5、实例方法
|
||||
|
||||
`Date`的实例对象,有几十个自己的方法,除了`valueOf`和`toString`,可以分为以下三类。
|
||||
|
||||
|
|
@ -4126,7 +4126,7 @@ d // Sun Jan 06 2013 06:00:00 GMT+0800 (CST)
|
|||
|
||||
## 十、RegExp 对象
|
||||
|
||||
`RegExp`对象提供正则表达式的功能。
|
||||
`RegExp`对象提供正则表达式的功能。
|
||||
|
||||
## 1、概述
|
||||
|
||||
|
|
@ -4464,8 +4464,8 @@ str.replace(/^\s+|\s+$/g, '')
|
|||
$n 用于组内容,$2为匹配到的第二组,即world; $1为匹配到的第一组,即hello
|
||||
*/
|
||||
|
||||
'abc'.replace('b', '[$`-$&-$\'-$$]')
|
||||
// "a[a-b-c-$]c"
|
||||
'abc'.replace('b', '[$`-$&-$\'-$$]')
|
||||
// "a[a-b-c-$]c"
|
||||
/*说明:
|
||||
$`为匹配结果 b 前面的文本,即 a
|
||||
$&为匹配的子字符串,即 b
|
||||
|
|
@ -4590,7 +4590,7 @@ str.split(separator, [limit])
|
|||
|
||||
|
||||
|
||||
正则表达式的规则很复杂,下面一一介绍这些规则。
|
||||
正则表达式的规则很复杂,下面一一介绍这些规则。
|
||||
|
||||
### 5.1 字面量字符和元字符
|
||||
|
||||
|
|
@ -4716,7 +4716,7 @@ str.split(separator, [limit])
|
|||
|
||||
- `\uhhhh` 匹配一个以四位十六进制数(`\u0000`-`\uFFFF`)表示的 Unicode 字符。
|
||||
|
||||
|
||||
|
||||
|
||||
### 5.4 字符类
|
||||
|
||||
|
|
@ -4755,7 +4755,7 @@ s.match(/yes[^]*day/) // [ 'yes\nmake my day']
|
|||
|
||||
> 注意,脱字符只有在字符类的第一个位置才有特殊含义,否则就是字面含义。
|
||||
|
||||
##### (2)连字符(- 字符连续范围)
|
||||
##### (2)连字符(- 字符连续范围)
|
||||
|
||||
某些情况下,对于连续序列的字符,连字符(`-`)用来提供简写形式,表示**字符的连续范围**。比如,`[abc]`可以写成`[a-c]`,`[0123456789]`可以写成`[0-9]`,同理`[A-Z]`表示26个大写字母。
|
||||
|
||||
|
|
@ -5422,7 +5422,7 @@ JSON.stringify({ p1: 1, p2: 2 }, null, 2);
|
|||
|
||||
|
||||
|
||||
JSON.stringify({ p1:1, p2:2 }, null, '|-');
|
||||
JSON.stringify({ p1:1, p2:2 }, null, '|-');
|
||||
/*
|
||||
"{
|
||||
|-"p1": 1,
|
||||
|
|
@ -5561,4 +5561,4 @@ JSON.parse('{"a": 1, "b": 2}', f)
|
|||
|
||||
## 文档
|
||||
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
title: 面向对象
|
||||
date: 2020-01-12 11:49:16
|
||||
permalink: /pages/659b5af5e2e704e0
|
||||
categories:
|
||||
categories:
|
||||
- 《JavaScript教程》笔记
|
||||
tags:
|
||||
- null
|
||||
author:
|
||||
tags:
|
||||
- JavaScript
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -91,7 +91,7 @@ var Vehicle = function () {
|
|||
|
||||
#### 基本用法
|
||||
|
||||
`new`命令的作用:**执行构造函数,返回一个实例对象**。
|
||||
`new`命令的作用:**执行构造函数,返回一个实例对象**。
|
||||
|
||||
```js
|
||||
var Vehicle = function () {
|
||||
|
|
@ -102,9 +102,9 @@ var v = new Vehicle(); // new 执行一个构造函数,返回一个实例对
|
|||
v.price // 1000
|
||||
```
|
||||
|
||||
上面代码通过`new`命令,让构造函数`Vehicle`生成一个实例对象,保存在变量`v`中。这个新生成的实例对象,从构造函数`Vehicle`得到了`price`属性。`new`命令执行时,构造函数内部的`this`,就代表了新生成的实例对象,`this.price`表示实例对象有一个`price`属性,值是1000。
|
||||
上面代码通过`new`命令,让构造函数`Vehicle`生成一个实例对象,保存在变量`v`中。这个新生成的实例对象,从构造函数`Vehicle`得到了`price`属性。`new`命令执行时,构造函数内部的`this`,就代表了新生成的实例对象,`this.price`表示实例对象有一个`price`属性,值是1000。
|
||||
|
||||
使用`new`命令时,根据需要,**构造函数也可以接受参数**。
|
||||
使用`new`命令时,根据需要,**构造函数也可以接受参数**。
|
||||
|
||||
```js
|
||||
var Vehicle = function (p) {
|
||||
|
|
@ -152,9 +152,9 @@ Fubar()
|
|||
// TypeError: Cannot set property '_foo' of undefined
|
||||
```
|
||||
|
||||
上面代码的`Fubar`为构造函数,`use strict`命令保证了该函数在严格模式下运行。由于**严格模式中,函数内部的`this`不能指向全局对象**,默认等于`undefined`,导致不加`new`调用会报错(JavaScript 不允许对`undefined`添加属性)。
|
||||
上面代码的`Fubar`为构造函数,`use strict`命令保证了该函数在严格模式下运行。由于**严格模式中,函数内部的`this`不能指向全局对象**,默认等于`undefined`,导致不加`new`调用会报错(JavaScript 不允许对`undefined`添加属性)。
|
||||
|
||||
**另一个解决办法**,构造函数内部判断是否使用`new`命令,如果发现没有使用,则直接返回一个实例对象。
|
||||
**另一个解决办法**,构造函数内部判断是否使用`new`命令,如果发现没有使用,则直接返回一个实例对象。
|
||||
|
||||
```js
|
||||
function Fubar(foo, bar) {
|
||||
|
|
@ -190,9 +190,9 @@ Fubar(1, 2)._foo // 1
|
|||
|
||||
5. 返回实例对象(或自定义对象)
|
||||
|
||||
|
||||
|
||||
也就是说,构造函数内部,`this`指的是一个新生成的空对象,**所有针对`this`的操作,都会发生在这个空对象上**。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即`this`对象),将其“构造”为需要的样子。
|
||||
|
||||
也就是说,构造函数内部,`this`指的是一个新生成的空对象,**所有针对`this`的操作,都会发生在这个空对象上**。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即`this`对象),将其“构造”为需要的样子。
|
||||
|
||||
如果构造函数内部有`return`语句,而且`return`后面跟着一个对象,`new`命令会返回`return`语句指定的对象;否则,就会不管`return`语句,返回`this`对象。
|
||||
|
||||
|
|
@ -200,7 +200,7 @@ Fubar(1, 2)._foo // 1
|
|||
var Vehicle = function () {
|
||||
this.price = 1000;
|
||||
return 1000; // 1000 非对象,被忽略,返回的是this对象;如果是return {},则会返回{}
|
||||
|
||||
|
||||
};
|
||||
|
||||
(new Vehicle()) === 1000
|
||||
|
|
@ -236,7 +236,7 @@ msg // {}
|
|||
typeof msg // "object"
|
||||
```
|
||||
|
||||
上面代码中,`getMessage`是一个普通函数,返回一个字符串。对它使用`new`命令,会得到一个空对象。这是因为**`new`命令总是返回一个对象,要么是实例对象,要么是`return`语句指定的对象**。本例中,`return`语句返回的是字符串,所以`new`命令就忽略了该语句。
|
||||
上面代码中,`getMessage`是一个普通函数,返回一个字符串。对它使用`new`命令,会得到一个空对象。这是因为**`new`命令总是返回一个对象,要么是实例对象,要么是`return`语句指定的对象**。本例中,`return`语句返回的是字符串,所以`new`命令就忽略了该语句。
|
||||
|
||||
`new`命令简化的内部流程,可以用下面的代码表示。
|
||||
|
||||
|
|
@ -470,7 +470,7 @@ function validate(obj, lowval, hival){
|
|||
|
||||
上面代码是一个文本输入框,每当用户输入一个值,就会调用`onChange`回调函数,验证这个值是否在指定范围。浏览器会向回调函数传入当前对象,因此`this`就代表传入当前对象(即文本框),然后就可以从`this.value`上面读到用户的输入值。
|
||||
|
||||
总结一下,**JavaScript 语言之中,一切皆对象,运行环境也是对象,所以函数都是在某个对象之中运行,`this`就是函数运行时所在的对象(环境)**。这本来并不会让用户糊涂,但是 JavaScript 支持运行环境动态切换,也就是说,`this`的指向是动态的,没有办法事先确定到底指向哪个对象,这才是最让初学者感到困惑的地方。
|
||||
总结一下,**JavaScript 语言之中,一切皆对象,运行环境也是对象,所以函数都是在某个对象之中运行,`this`就是函数运行时所在的对象(环境)**。这本来并不会让用户糊涂,但是 JavaScript 支持运行环境动态切换,也就是说,`this`的指向是动态的,没有办法事先确定到底指向哪个对象,这才是最让初学者感到困惑的地方。
|
||||
|
||||
|
||||
|
||||
|
|
@ -499,7 +499,7 @@ var obj = { foo: 5 };
|
|||
|
||||
注意,`foo`属性的值保存在属性描述对象的`value`属性里面。
|
||||
|
||||
这样的结构是很清晰的,问题在于属性的值可能是一个函数。
|
||||
这样的结构是很清晰的,问题在于属性的值可能是一个函数。
|
||||
|
||||
```js
|
||||
var obj = { foo: function () {} };
|
||||
|
|
@ -571,7 +571,7 @@ obj.f() // 2 f方法当前运行环境为obj对象
|
|||
|
||||
### 3、使用场合
|
||||
|
||||
`this`主要有以下几个使用场合。
|
||||
`this`主要有以下几个使用场合。
|
||||
|
||||
#### (1)全局环境
|
||||
|
||||
|
|
@ -604,7 +604,7 @@ o.p // "Hello World!"
|
|||
|
||||
|
||||
|
||||
#### (3)对象的方法
|
||||
#### (3)对象的方法
|
||||
|
||||
如果对象的方法里面包含`this`,`this`的指向就是方法运行时所在的对象。该方法赋值给另一个对象,就会改变`this`的指向。
|
||||
|
||||
|
|
@ -734,7 +734,7 @@ hello.m() // Hello this指向不变
|
|||
|
||||
#### (1)避免多层 this
|
||||
|
||||
由于`this`的指向是不确定的,所以切勿在函数中包含多层的`this`。
|
||||
由于`this`的指向是不确定的,所以切勿在函数中包含多层的`this`。
|
||||
|
||||
```js
|
||||
var o = {
|
||||
|
|
@ -825,7 +825,7 @@ o.f()
|
|||
// undefined a2
|
||||
```
|
||||
|
||||
上面代码中,`foreach`方法的回调函数中的`this`,其实是指向`window`对象,因此取不到`o.v`的值。原因跟上一段的多层`this`是一样的,就是内层的`this`不指向外部,而指向顶层对象。
|
||||
上面代码中,`foreach`方法的回调函数中的`this`,其实是指向`window`对象,因此取不到`o.v`的值。原因跟上一段的多层`this`是一样的,就是内层的`this`不指向外部,而指向顶层对象。
|
||||
|
||||
解决这个问题的一种方法,就是前面提到的,使用中间变量固定`this`。
|
||||
|
||||
|
|
@ -904,7 +904,7 @@ $('#button').on('click', o.f);
|
|||
|
||||
### 5、绑定 this 的方法
|
||||
|
||||
`this`的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把`this`固定下来,避免出现意想不到的情况。JavaScript 提供了`call`、`apply`、`bind`这三个方法,来切换/固定`this`的指向。
|
||||
`this`的动态切换,固然为 JavaScript 创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把`this`固定下来,避免出现意想不到的情况。JavaScript 提供了`call`、`apply`、`bind`这三个方法,来切换/固定`this`的指向。
|
||||
|
||||
#### Function.prototype.call()
|
||||
|
||||
|
|
@ -943,7 +943,7 @@ a.call(window) // 123
|
|||
a.call(obj) // 456
|
||||
```
|
||||
|
||||
上面代码中,`a`函数中的`this`关键字,如果指向全局对象,返回结果为`123`。如果使用`call`方法将`this`关键字指向`obj`对象,返回结果为`456`。可以看到,如果`call`方法没有参数,或者参数为`null`或`undefined`,则等同于指向全局对象。
|
||||
上面代码中,`a`函数中的`this`关键字,如果指向全局对象,返回结果为`123`。如果使用`call`方法将`this`关键字指向`obj`对象,返回结果为`456`。可以看到,如果`call`方法没有参数,或者参数为`null`或`undefined`,则等同于指向全局对象。
|
||||
|
||||
如果`call`方法的参数是一个原始值,那么这个**原始值会自动转成对应的包装对象**,然后传入`call`方法。
|
||||
|
||||
|
|
@ -982,7 +982,7 @@ add.call(this, 1, 2) // 3
|
|||
|
||||
##### 应用:调用对象的原生方法
|
||||
|
||||
`call`方法的一个应用是调用对象的原生方法。
|
||||
`call`方法的一个应用是调用对象的原生方法。
|
||||
|
||||
```JS
|
||||
var obj = {};
|
||||
|
|
@ -1041,7 +1041,7 @@ func.apply(thisValue, [arg1, arg2, ...])
|
|||
// 第二个参数为一个数组,数组每一项为传入函数的参数
|
||||
```
|
||||
|
||||
`apply`方法的第一个参数也是`this`所要指向的那个对象,如果设为`null`或`undefined`,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。原函数的参数,在`call`方法中必须一个个添加,但是在`apply`方法中,必须以数组形式添加。
|
||||
`apply`方法的第一个参数也是`this`所要指向的那个对象,如果设为`null`或`undefined`,则等同于指定全局对象。第二个参数则是一个数组,该数组的所有成员依次作为参数,传入原函数。原函数的参数,在`call`方法中必须一个个添加,但是在`apply`方法中,必须以数组形式添加。
|
||||
|
||||
```js
|
||||
function f(x, y){
|
||||
|
|
@ -1077,7 +1077,7 @@ var a = [10, 2, 4, 15, 9];
|
|||
Math.min.apply(null, a) // 15 null等于绑定全局对象
|
||||
```
|
||||
|
||||
##### (2)将数组的空元素变为`undefined`
|
||||
##### (2)将数组的空元素变为`undefined`
|
||||
|
||||
通过`apply`方法,利用`Array`构造函数将数组的空元素变成`undefined`。
|
||||
|
||||
|
|
@ -1105,7 +1105,7 @@ Array.apply(null, a).forEach(print)
|
|||
// b
|
||||
```
|
||||
|
||||
##### (3)转换类似数组的对象
|
||||
##### (3)转换类似数组的对象
|
||||
|
||||
另外,利用数组对象的`slice`方法,可以将一个类似数组的对象(比如`arguments`对象)转为真正的数组。
|
||||
|
||||
|
|
@ -1165,7 +1165,7 @@ var print = d.getTime;
|
|||
print() // Uncaught TypeError: this is not a Date object.
|
||||
```
|
||||
|
||||
上面代码中,我们将`d.getTime`方法赋给变量`print`,然后调用`print`就报错了。这是因为`getTime`方法内部的`this`,绑定`Date`对象的实例,赋给变量`print`以后,内部的`this`已经不指向`Date`对象的实例了。
|
||||
上面代码中,我们将`d.getTime`方法赋给变量`print`,然后调用`print`就报错了。这是因为`getTime`方法内部的`this`,绑定`Date`对象的实例,赋给变量`print`以后,内部的`this`已经不指向`Date`对象的实例了。
|
||||
|
||||
`bind`方法可以解决这个问题。
|
||||
|
||||
|
|
@ -1176,7 +1176,7 @@ print() // 1481869925657
|
|||
|
||||
上面代码中,`bind`方法将`getTime`方法内部的`this`绑定到`d`对象,这时就可以安全地将这个方法赋值给其他变量了。
|
||||
|
||||
`bind`方法的参数就是所要绑定`this`的对象,下面是一个更清晰的例子。
|
||||
`bind`方法的参数就是所要绑定`this`的对象,下面是一个更清晰的例子。
|
||||
|
||||
```js
|
||||
var counter = {
|
||||
|
|
@ -1246,7 +1246,7 @@ plus5(10) // 15 传入的参数为add内的y
|
|||
|
||||
##### bind要注意的点:
|
||||
|
||||
##### (1)每一次返回一个新函数
|
||||
##### (1)每一次返回一个新函数
|
||||
|
||||
`bind`方法**每运行一次,就返回一个新函数**,这会产生一些问题。比如,监听事件的时候,不能写成下面这样。
|
||||
|
||||
|
|
@ -1416,7 +1416,7 @@ ES6 引入了 class 语法,基于 class 的继承不在这个教程介绍,
|
|||
|
||||
### 1、原型对象概述
|
||||
|
||||
#### (1)构造函数的缺点
|
||||
#### (1)构造函数的缺点
|
||||
|
||||
JavaScript 通过构造函数生成新对象,因此**构造函数可以视为对象的模板**。实例对象的属性和方法,可以定义在构造函数内部。
|
||||
|
||||
|
|
@ -1480,7 +1480,7 @@ typeof f.prototype // "object"
|
|||
|
||||
上面代码中,函数`f`默认具有`prototype`属性,指向一个对象。
|
||||
|
||||
**对于普通函数来说,该属性基本无用**。但是,**对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型**。
|
||||
**对于普通函数来说,该属性基本无用**。但是,**对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型**。
|
||||
|
||||
```js
|
||||
function Animal(name) {
|
||||
|
|
@ -1505,7 +1505,7 @@ Animal.prototype.color = 'yellow';
|
|||
|
||||
|
||||
// color属性并非实例对象cat1/cat2本身的属性,只是当实例本身没有该属性或方法时,它会到原型对象去寻找该属性或方法
|
||||
cat1.color // "yellow"
|
||||
cat1.color // "yellow"
|
||||
cat2.color // "yellow"
|
||||
```
|
||||
|
||||
|
|
@ -1570,7 +1570,7 @@ mine instanceof Array // true 判断实例对象mine是否为构造函数Array
|
|||
|
||||
上面代码中,`mine`是构造函数`MyArray`的实例对象,由于`MyArray.prototype`指向一个数组实例,使得`mine`可以调用数组方法(这些方法定义在数组实例的`prototype`对象上面)。最后那行`instanceof`表达式,用来比较一个对象是否为某个构造函数的实例,结果就是证明`mine`为`Array`的实例,`instanceof`运算符的详细解释详见后文。
|
||||
|
||||
上面代码还出现了原型对象的`constructor`属性,这个属性的含义下一节就来解释。
|
||||
上面代码还出现了原型对象的`constructor`属性,这个属性的含义下一节就来解释。
|
||||
|
||||
#### (4)constructor 属性
|
||||
|
||||
|
|
@ -1642,7 +1642,7 @@ Person.prototype = { // 修改了原型对象,但没有修改原型下的constru
|
|||
};
|
||||
|
||||
// 由于原型对象已被修改,原型下的constructor也被修改
|
||||
Person.prototype.constructor === Person // false
|
||||
Person.prototype.constructor === Person // false
|
||||
Person.prototype.constructor === Object // true // 普通对象的constructor指向object构造函数
|
||||
```
|
||||
|
||||
|
|
@ -1680,7 +1680,7 @@ f.constructor.name // "Foo"
|
|||
|
||||
### 2、instanceof 运算符
|
||||
|
||||
`instanceof`运算符,**判断对象是否为某个构造函数的实例,返回一个布尔值**。
|
||||
`instanceof`运算符,**判断对象是否为某个构造函数的实例,返回一个布尔值**。
|
||||
|
||||
#### 语法
|
||||
|
||||
|
|
@ -1819,7 +1819,7 @@ Sub.prototype.method = '...';
|
|||
|
||||
|
||||
|
||||
**另外一种写法**是`Sub.prototype`等于一个父类实例。
|
||||
**另外一种写法**是`Sub.prototype`等于一个父类实例。
|
||||
|
||||
```js
|
||||
Sub.prototype = new Super();// 这个写法会继承父类实例的方法,不推荐
|
||||
|
|
@ -1882,7 +1882,7 @@ ClassB.prototype.print = function() {// 单个方法的继承
|
|||
|
||||
### 4、多重继承
|
||||
|
||||
JavaScript 不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能。
|
||||
JavaScript 不提供多重继承功能,即不允许一个对象同时继承多个对象。但是,可以通过变通方法,实现这个功能。
|
||||
|
||||
```js
|
||||
function M1() { // 构造函数M1
|
||||
|
|
@ -2099,7 +2099,7 @@ var module1 = (function ($, YAHOO) {
|
|||
|
||||
## 四、Object 对象的相关方法
|
||||
|
||||
JavaScript 在`Object`对象上面,提供了很多相关方法,处理面向对象编程的相关操作。本章介绍这些方法。
|
||||
JavaScript 在`Object`对象上面,提供了很多相关方法,处理面向对象编程的相关操作。本章介绍这些方法。
|
||||
|
||||
### 1、Object.getPrototypeOf() 获取原型对象
|
||||
|
||||
|
|
@ -2131,7 +2131,7 @@ Object.getPrototypeOf(f) === Function.prototype // true
|
|||
|
||||
### 2、Object.setPrototypeOf() 设置原型对象
|
||||
|
||||
`Object.setPrototypeOf`方法为参数对象**设置原型**,**返回该参数对象**。它接受两个参数,第一个是现有对象,第二个是原型对象。
|
||||
`Object.setPrototypeOf`方法为参数对象**设置原型**,**返回该参数对象**。它接受两个参数,第一个是现有对象,第二个是原型对象。
|
||||
|
||||
```js
|
||||
var a = {};
|
||||
|
|
@ -2157,7 +2157,7 @@ var f = Object.setPrototypeOf({}, F.prototype); // 模拟new命令
|
|||
F.call(f);
|
||||
```
|
||||
|
||||
上面代码中,`new`命令新建实例对象,其实可以分成两步。第一步,将一个空对象的原型设为构造函数的`prototype`属性(上例是`F.prototype`);第二步,将构造函数内部的`this`绑定这个空对象,然后执行构造函数,使得定义在`this`上面的方法和属性(上例是`this.foo`),都转移到这个空对象上。
|
||||
上面代码中,`new`命令新建实例对象,其实可以分成两步。第一步,将一个空对象的原型设为构造函数的`prototype`属性(上例是`F.prototype`);第二步,将构造函数内部的`this`绑定这个空对象,然后执行构造函数,使得定义在`this`上面的方法和属性(上例是`this.foo`),都转移到这个空对象上。
|
||||
|
||||
### 3、 Object.create() 创建实例对象,指向目标对象的原型
|
||||
|
||||
|
|
@ -2218,7 +2218,7 @@ obj.valueOf()
|
|||
// TypeError: Object [object Object] has no method 'valueOf'
|
||||
```
|
||||
|
||||
上面代码中,对象`obj`的原型是`null`,它就不具备一些定义在`Object.prototype`对象上面的属性,比如`valueOf`方法。
|
||||
上面代码中,对象`obj`的原型是`null`,它就不具备一些定义在`Object.prototype`对象上面的属性,比如`valueOf`方法。
|
||||
|
||||
使用`Object.create`方法的时候,必须提供对象原型,即**参数不能为空,或者不是对象,否则会报错**。
|
||||
|
||||
|
|
@ -2241,7 +2241,7 @@ obj2.p // 2 obj2的原型指向obj1,当访问obj2上的p属性时,js引擎
|
|||
|
||||
上面代码中,修改对象原型`obj1`会影响到实例对象`obj2`。
|
||||
|
||||
除了对象的原型,`Object.create`方法还可以接受**第二个参数。该参数是一个属性描述对象,它所描述的对象属性,会添加到实例对象,作为该对象自身的属性**。
|
||||
除了对象的原型,`Object.create`方法还可以接受**第二个参数。该参数是一个属性描述对象,它所描述的对象属性,会添加到实例对象,作为该对象自身的属性**。
|
||||
|
||||
```js
|
||||
var obj = Object.create({}, {
|
||||
|
|
@ -2306,7 +2306,7 @@ Object.prototype.isPrototypeOf(Object.create(null)) // false
|
|||
|
||||
### 5、Object.prototype.\_\_proto\_\_ 返回该对象的原型,可读写
|
||||
|
||||
实例对象的`__proto__`**属性**(前后各两个下划线),**返回该对象的原型。该属性可读写**。
|
||||
实例对象的`__proto__`**属性**(前后各两个下划线),**返回该对象的原型。该属性可读写**。
|
||||
|
||||
```js
|
||||
var obj = Object.create({x:1}) // 创建实例对象obj,其原型指定为{x:1}
|
||||
|
|
@ -2327,7 +2327,7 @@ obj.__proto__ === Object.getPrototypeOf(obj) //true
|
|||
|
||||
上面代码通过`__proto__`属性,将`p`对象设为`obj`对象的原型。
|
||||
|
||||
根据语言标准,`__proto__`属性只有浏览器才需要部署,其他环境可以没有这个属性。它前后的两根下划线,表明它本质是一个内部属性,不应该对使用者暴露。**因此,应该尽量少用这个属性,而是用`Object.getPrototypeOf()`和`Object.setPrototypeOf()`,进行原型对象的读写操作**。
|
||||
根据语言标准,`__proto__`属性只有浏览器才需要部署,其他环境可以没有这个属性。它前后的两根下划线,表明它本质是一个内部属性,不应该对使用者暴露。**因此,应该尽量少用这个属性,而是用`Object.getPrototypeOf()`和`Object.setPrototypeOf()`,进行原型对象的读写操作**。
|
||||
|
||||
原型链可以用`__proto__`很直观地表示。
|
||||
|
||||
|
|
@ -2402,7 +2402,7 @@ C.prototype = p;
|
|||
C.prototype.constructor = C; // 如在构造函数的继承中就使用到这个操作
|
||||
|
||||
var c = new C();
|
||||
c.constructor.prototype === p // true
|
||||
c.constructor.prototype === p // true
|
||||
```
|
||||
|
||||
因此,**推荐使用第三种`Object.getPrototypeOf`方法,获取原型对象**。
|
||||
|
|
@ -2466,7 +2466,7 @@ var o2 = Object.create(o1, { // o2的原型指向o1,并且在o2上定义一个
|
|||
for (p in o2) {
|
||||
console.info(p);
|
||||
}
|
||||
// p2
|
||||
// p2
|
||||
// p1 继承的属性
|
||||
```
|
||||
|
||||
|
|
@ -2526,7 +2526,7 @@ inheritedPropertyNames(Date)
|
|||
```js
|
||||
function copyObject(orig) { // 拷贝对象函数
|
||||
// 创建一个新对象,新对象的原型指向旧对象的原型
|
||||
var copy = Object.create(Object.getPrototypeOf(orig));
|
||||
var copy = Object.create(Object.getPrototypeOf(orig));
|
||||
copyOwnPropertiesFrom(copy, orig);
|
||||
return copy;
|
||||
}
|
||||
|
|
@ -2586,9 +2586,4 @@ function copyObject(orig) {
|
|||
|
||||
## 文档
|
||||
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
title: 异步操作
|
||||
date: 2020-01-12 11:49:16
|
||||
permalink: /pages/d61b1cb4cdac1f63
|
||||
categories:
|
||||
categories:
|
||||
- 《JavaScript教程》笔记
|
||||
tags:
|
||||
- null
|
||||
author:
|
||||
tags:
|
||||
- JavaScript
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -62,7 +62,7 @@ JavaScript 引擎怎么知道异步任务有没有结果,能不能进入主线
|
|||
|
||||
#### (1)回调函数
|
||||
|
||||
回调函数**是异步操作最基本的方法。**
|
||||
回调函数**是异步操作最基本的方法。**
|
||||
|
||||
下面是两个函数`f1`和`f2`,编程的意图是`f2`必须等到`f1`执行完成,才能执行。
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ f1(f2);
|
|||
|
||||
#### (2)事件监听
|
||||
|
||||
另一种思路是采用事件驱动模式。**异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生**。
|
||||
另一种思路是采用事件驱动模式。**异步任务的执行不取决于代码的顺序,而取决于某个事件是否发生**。
|
||||
|
||||
还是以`f1`和`f2`为例。首先,为`f1`绑定一个事件(这里采用的 jQuery 的[写法](https://api.jquery.com/on/))。
|
||||
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
title: DOM
|
||||
date: 2020-01-12 11:49:16
|
||||
permalink: /pages/7d961b8030c6099e
|
||||
categories:
|
||||
categories:
|
||||
- 《JavaScript教程》笔记
|
||||
tags:
|
||||
- null
|
||||
author:
|
||||
tags:
|
||||
- JavaScript
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -69,7 +69,7 @@ DOM 提供操作接口,用来获取这三种关系的节点。比如,子节
|
|||
|
||||
## 二、Node接口
|
||||
|
||||
**所有 DOM 节点对象都继承了 Node 接口,拥有一些共同的属性和方法**。这是 DOM 操作的基础。
|
||||
**所有 DOM 节点对象都继承了 Node 接口,拥有一些共同的属性和方法**。这是 DOM 操作的基础。
|
||||
|
||||
### 1、属性
|
||||
|
||||
|
|
@ -659,7 +659,7 @@ p1.isSameNode(p2) // false
|
|||
p1.isSameNode(p1) // true
|
||||
```
|
||||
|
||||
#### 2.10 Node.prototype.normalize() 将当前节点和它的后代节点”规范化“
|
||||
#### 2.10 Node.prototype.normalize() 将当前节点和它的后代节点”规范化“
|
||||
|
||||
`normalize`方法 **将当前节点和它的后代节点”规范化“** 。在一个"规范化"后的DOM树中,不存在一个空的文本节点,或者两个相邻的文本节点。
|
||||
|
||||
|
|
@ -905,22 +905,22 @@ document.images.pic === pic // true
|
|||
<script>
|
||||
var li1 = document.getElementById('li1');
|
||||
var li2 = document.querySelector('#li1');
|
||||
|
||||
|
||||
var li3 = document.getElementsByClassName('li2');
|
||||
var li4 = document.getElementsByTagName('li');
|
||||
|
||||
|
||||
var li5 = document.getElementsByName('liName');
|
||||
var li6 = document.querySelectorAll('li');
|
||||
|
||||
|
||||
console.log(li1) // <li id="li1"></li>
|
||||
console.log(li2) // <li id="li1"></li>
|
||||
|
||||
|
||||
console.log(li3) // HTMLCollection [li.li2]
|
||||
console.log(li4) // HTMLCollection(3) [li#li1, li.li2, li, li1: li#li1, liName: li]
|
||||
|
||||
|
||||
console.log(li5) // NodeList [li]
|
||||
console.log(li6) // NodeList(3) [li#li1, li.li2, li]
|
||||
|
||||
|
||||
</script>
|
||||
```
|
||||
|
||||
|
|
@ -969,7 +969,7 @@ document.images.namedItem('pic') === pic // true
|
|||
|
||||
## 四、ParentNode 接口(父节点接口),ChildNode 接口(子节点接口)
|
||||
|
||||
节点对象除了继承 Node 接口以外,还会继承其他接口。`ParentNode`接口**表示当前节点是一个父节点,提供一些处理子节点的方法**。`ChildNode`接口**表示当前节点是一个子节点,提供一些相关方法。**
|
||||
节点对象除了继承 Node 接口以外,还会继承其他接口。`ParentNode`接口**表示当前节点是一个父节点,提供一些处理子节点的方法**。`ChildNode`接口**表示当前节点是一个子节点,提供一些相关方法。**
|
||||
|
||||
|
||||
|
||||
|
|
@ -1176,7 +1176,7 @@ doctype.name // "html"
|
|||
|
||||
|
||||
|
||||
##### (4)document.body 指向\<body\>,document.head 指向 \<head\>
|
||||
##### (4)document.body 指向\<body\>,document.head 指向 \<head\>
|
||||
|
||||
`document.body`属性指向` <body> `节点,`document.head`属性指向` <head> `节点。
|
||||
|
||||
|
|
@ -1221,7 +1221,7 @@ if (document.fullscreenElement.nodeName == 'VIDEO') {
|
|||
|
||||
#### 2.2 节点集合属性 (文档内部特定元素的集合,返HTMLCollection实例)
|
||||
|
||||
以下属性**返回一个`HTMLCollection`实例**,表示文档内部特定元素的集合。这些集合都是**动态的**,原节点有任何变化,立刻会反映在集合中。
|
||||
以下属性**返回一个`HTMLCollection`实例**,表示文档内部特定元素的集合。这些集合都是**动态的**,原节点有任何变化,立刻会反映在集合中。
|
||||
|
||||
##### (1)document.links 返回所有含href属性的<a\>和<area\>
|
||||
|
||||
|
|
@ -1420,7 +1420,7 @@ document.referrer
|
|||
|
||||
`document.dir`返回**一个字符串,表示文字方向**。它**只有两个可能**的值:`rtl`表示文字从右到左,阿拉伯文是这种方式;`ltr`表示文字从左到右,包括英语和汉语在内的大多数文字采用这种方式。
|
||||
|
||||
> 注: 第一次调用该属性时,可能返回空字符串""
|
||||
> 注: 第一次调用该属性时,可能返回空字符串""
|
||||
|
||||
|
||||
|
||||
|
|
@ -2037,10 +2037,10 @@ var nodeIterator = document.createNodeIterator(document.body);
|
|||
var pars = [];
|
||||
var currentNode;
|
||||
|
||||
while (currentNode = nodeIterator.nextNode()) {
|
||||
while (currentNode = nodeIterator.nextNode()) {
|
||||
// js中所有运算符都有返回值,为运算结果。这里面即给currentNode赋值了,还会自动调用Boolean()进行布尔运算。
|
||||
// 每次调用NodeFilter实例的nextNode()方法都会返回下一个节点
|
||||
|
||||
|
||||
pars.push(currentNode);
|
||||
}
|
||||
```
|
||||
|
|
@ -2098,9 +2098,9 @@ while(treeWalker.nextNode()) {
|
|||
|
||||
##### (1)document.execCommand() 执行命令(实现复制文本等功能,富文本编辑器大量使用此方法)
|
||||
|
||||
概念一: **当一个HTML文档切换到设计模式时,`document`暴露 `execCommand` 方法,该方法允许运行命令来操纵[可编辑内容区域](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/contenteditable)的元素。**
|
||||
概念一: **当一个HTML文档切换到设计模式时,`document`暴露 `execCommand` 方法,该方法允许运行命令来操纵[可编辑内容区域](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Global_attributes/contenteditable)的元素。**
|
||||
|
||||
概念二: **execCommand方法是执行一个对当前文档,当前选择或者给出范围的命令。处理Html数据时常用**
|
||||
概念二: **execCommand方法是执行一个对当前文档,当前选择或者给出范围的命令。处理Html数据时常用**
|
||||
|
||||
|
||||
|
||||
|
|
@ -2139,159 +2139,159 @@ if (url) {
|
|||
###### 命令列表
|
||||
|
||||
```css
|
||||
1. 2D-Position 允许通过拖曳移动绝对定位的对象。
|
||||
1. 2D-Position 允许通过拖曳移动绝对定位的对象。
|
||||
|
||||
2. AbsolutePosition 设定元素的 position 属性为“absolute”(绝对)。
|
||||
2. AbsolutePosition 设定元素的 position 属性为“absolute”(绝对)。
|
||||
|
||||
3. BackColor 设置或获取当前选中区的背景颜色。
|
||||
3. BackColor 设置或获取当前选中区的背景颜色。
|
||||
|
||||
4. BlockDirLTR 目前尚未支持。
|
||||
4. BlockDirLTR 目前尚未支持。
|
||||
|
||||
5. BlockDirRTL 目前尚未支持。
|
||||
5. BlockDirRTL 目前尚未支持。
|
||||
|
||||
6. Bold 切换当前选中区的粗体显示与否。
|
||||
6. Bold 切换当前选中区的粗体显示与否。
|
||||
|
||||
7. BrowseMode 目前尚未支持。
|
||||
7. BrowseMode 目前尚未支持。
|
||||
|
||||
8. Copy 将当前选中区复制到剪贴板。
|
||||
8. Copy 将当前选中区复制到剪贴板。
|
||||
|
||||
9. CreateBookmark 创建一个书签锚或获取当前选中区或插入点的书签锚的名称。
|
||||
9. CreateBookmark 创建一个书签锚或获取当前选中区或插入点的书签锚的名称。
|
||||
|
||||
10.CreateLink 在当前选中区上插入超级链接,或显示一个对话框允许用户指定要为当前选中区插入的超级链接的 URL。
|
||||
10.CreateLink 在当前选中区上插入超级链接,或显示一个对话框允许用户指定要为当前选中区插入的超级链接的 URL。
|
||||
|
||||
11.Cut 将当前选中区复制到剪贴板并删除之。
|
||||
11.Cut 将当前选中区复制到剪贴板并删除之。
|
||||
|
||||
12.Delete 删除当前选中区。
|
||||
12.Delete 删除当前选中区。
|
||||
|
||||
13.DirLTR 目前尚未支持。
|
||||
13.DirLTR 目前尚未支持。
|
||||
|
||||
14.DirRTL 目前尚未支持。
|
||||
14.DirRTL 目前尚未支持。
|
||||
|
||||
15.EditMode 目前尚未支持。
|
||||
15.EditMode 目前尚未支持。
|
||||
|
||||
16.FontName 设置或获取当前选中区的字体。
|
||||
16.FontName 设置或获取当前选中区的字体。
|
||||
|
||||
17.FontSize 设置或获取当前选中区的字体大小。
|
||||
17.FontSize 设置或获取当前选中区的字体大小。
|
||||
|
||||
18.ForeColor 设置或获取当前选中区的前景(文本)颜色。
|
||||
18.ForeColor 设置或获取当前选中区的前景(文本)颜色。
|
||||
|
||||
19.FormatBlock 设置当前块格式化标签。
|
||||
19.FormatBlock 设置当前块格式化标签。
|
||||
|
||||
20.Indent 增加选中文本的缩进。
|
||||
20.Indent 增加选中文本的缩进。
|
||||
|
||||
21.InlineDirLTR 目前尚未支持。
|
||||
21.InlineDirLTR 目前尚未支持。
|
||||
|
||||
22.InlineDirRTL 目前尚未支持。
|
||||
22.InlineDirRTL 目前尚未支持。
|
||||
|
||||
23.InsertButton 用按钮控件覆盖当前选中区。
|
||||
23.InsertButton 用按钮控件覆盖当前选中区。
|
||||
|
||||
24.InsertFieldset 用方框覆盖当前选中区。
|
||||
24.InsertFieldset 用方框覆盖当前选中区。
|
||||
|
||||
25.InsertHorizontalRule 用水平线覆盖当前选中区。
|
||||
25.InsertHorizontalRule 用水平线覆盖当前选中区。
|
||||
|
||||
26.InsertIFrame 用内嵌框架覆盖当前选中区。
|
||||
26.InsertIFrame 用内嵌框架覆盖当前选中区。
|
||||
|
||||
27.InsertImage 用图像覆盖当前选中区。
|
||||
27.InsertImage 用图像覆盖当前选中区。
|
||||
|
||||
28.InsertInputButton 用按钮控件覆盖当前选中区。
|
||||
28.InsertInputButton 用按钮控件覆盖当前选中区。
|
||||
|
||||
29.InsertInputCheckbox 用复选框控件覆盖当前选中区。
|
||||
29.InsertInputCheckbox 用复选框控件覆盖当前选中区。
|
||||
|
||||
30.InsertInputFileUpload 用文件上载控件覆盖当前选中区。
|
||||
30.InsertInputFileUpload 用文件上载控件覆盖当前选中区。
|
||||
|
||||
31.InsertInputHidden 插入隐藏控件覆盖当前选中区。
|
||||
31.InsertInputHidden 插入隐藏控件覆盖当前选中区。
|
||||
|
||||
32.InsertInputImage 用图像控件覆盖当前选中区。
|
||||
32.InsertInputImage 用图像控件覆盖当前选中区。
|
||||
|
||||
33.InsertInputPassword 用密码控件覆盖当前选中区。
|
||||
33.InsertInputPassword 用密码控件覆盖当前选中区。
|
||||
|
||||
34.InsertInputRadio 用单选钮控件覆盖当前选中区。
|
||||
34.InsertInputRadio 用单选钮控件覆盖当前选中区。
|
||||
|
||||
35.InsertInputReset 用重置控件覆盖当前选中区。
|
||||
35.InsertInputReset 用重置控件覆盖当前选中区。
|
||||
|
||||
36.InsertInputSubmit 用提交控件覆盖当前选中区。
|
||||
36.InsertInputSubmit 用提交控件覆盖当前选中区。
|
||||
|
||||
37.InsertInputText 用文本控件覆盖当前选中区。
|
||||
37.InsertInputText 用文本控件覆盖当前选中区。
|
||||
|
||||
38.InsertMarquee 用空字幕覆盖当前选中区。
|
||||
38.InsertMarquee 用空字幕覆盖当前选中区。
|
||||
|
||||
39.InsertOrderedList 切换当前选中区是编号列表还是常规格式化块。
|
||||
39.InsertOrderedList 切换当前选中区是编号列表还是常规格式化块。
|
||||
|
||||
40.InsertParagraph 用换行覆盖当前选中区。
|
||||
40.InsertParagraph 用换行覆盖当前选中区。
|
||||
|
||||
41.InsertSelectDropdown 用下拉框控件覆盖当前选中区。
|
||||
41.InsertSelectDropdown 用下拉框控件覆盖当前选中区。
|
||||
|
||||
42.InsertSelectListbox 用列表框控件覆盖当前选中区。
|
||||
42.InsertSelectListbox 用列表框控件覆盖当前选中区。
|
||||
|
||||
43.InsertTextArea 用多行文本输入控件覆盖当前选中区。
|
||||
43.InsertTextArea 用多行文本输入控件覆盖当前选中区。
|
||||
|
||||
44.InsertUnorderedList 切换当前选中区是项目符号列表还是常规格式化块。
|
||||
44.InsertUnorderedList 切换当前选中区是项目符号列表还是常规格式化块。
|
||||
|
||||
45.Italic 切换当前选中区斜体显示与否。
|
||||
45.Italic 切换当前选中区斜体显示与否。
|
||||
|
||||
46.JustifyCenter 将当前选中区在所在格式化块置中。
|
||||
46.JustifyCenter 将当前选中区在所在格式化块置中。
|
||||
|
||||
47.JustifyFull 目前尚未支持。
|
||||
47.JustifyFull 目前尚未支持。
|
||||
|
||||
48.JustifyLeft 将当前选中区所在格式化块左对齐。
|
||||
48.JustifyLeft 将当前选中区所在格式化块左对齐。
|
||||
|
||||
49.JustifyNone 目前尚未支持。
|
||||
49.JustifyNone 目前尚未支持。
|
||||
|
||||
50.JustifyRight 将当前选中区所在格式化块右对齐。
|
||||
50.JustifyRight 将当前选中区所在格式化块右对齐。
|
||||
|
||||
51.LiveResize 迫使 MSHTML 编辑器在缩放或移动过程中持续更新元素外观,而不是只在移动或缩放完成后更新。
|
||||
51.LiveResize 迫使 MSHTML 编辑器在缩放或移动过程中持续更新元素外观,而不是只在移动或缩放完成后更新。
|
||||
|
||||
52.MultipleSelection 允许当用户按住 Shift 或 Ctrl 键时一次选中多于一个站点可选元素。
|
||||
52.MultipleSelection 允许当用户按住 Shift 或 Ctrl 键时一次选中多于一个站点可选元素。
|
||||
|
||||
53.Open 打开。
|
||||
53.Open 打开。
|
||||
|
||||
54.Outdent 减少选中区所在格式化块的缩进。
|
||||
54.Outdent 减少选中区所在格式化块的缩进。
|
||||
|
||||
55.OverWrite 切换文本状态的插入和覆盖。
|
||||
55.OverWrite 切换文本状态的插入和覆盖。
|
||||
|
||||
56.Paste 用剪贴板内容覆盖当前选中区。
|
||||
56.Paste 用剪贴板内容覆盖当前选中区。
|
||||
|
||||
57.PlayImage 目前尚未支持。
|
||||
57.PlayImage 目前尚未支持。
|
||||
|
||||
58.Print 打开打印对话框以便用户可以打印当前页。
|
||||
58.Print 打开打印对话框以便用户可以打印当前页。
|
||||
|
||||
59.Redo 重做。
|
||||
59.Redo 重做。
|
||||
|
||||
60.Refresh 刷新当前文档。
|
||||
60.Refresh 刷新当前文档。
|
||||
|
||||
61.RemoveFormat 从当前选中区中删除格式化标签。
|
||||
61.RemoveFormat 从当前选中区中删除格式化标签。
|
||||
|
||||
62.RemoveParaFormat 目前尚未支持。
|
||||
62.RemoveParaFormat 目前尚未支持。
|
||||
|
||||
63.SaveAs 将当前 Web 页面保存为文件。
|
||||
63.SaveAs 将当前 Web 页面保存为文件。
|
||||
|
||||
64.SelectAll 选中整个文档。
|
||||
64.SelectAll 选中整个文档。
|
||||
|
||||
65.SizeToControl 目前尚未支持。
|
||||
65.SizeToControl 目前尚未支持。
|
||||
|
||||
66.SizeToControlHeight 目前尚未支持。
|
||||
66.SizeToControlHeight 目前尚未支持。
|
||||
|
||||
67.SizeToControlWidth 目前尚未支持。
|
||||
67.SizeToControlWidth 目前尚未支持。
|
||||
|
||||
68.Stop 停止。
|
||||
68.Stop 停止。
|
||||
|
||||
69.StopImage 目前尚未支持。
|
||||
69.StopImage 目前尚未支持。
|
||||
|
||||
70.StrikeThrough 目前尚未支持。
|
||||
70.StrikeThrough 目前尚未支持。
|
||||
|
||||
71.Subscript 目前尚未支持。
|
||||
71.Subscript 目前尚未支持。
|
||||
|
||||
72.Superscript 目前尚未支持。
|
||||
72.Superscript 目前尚未支持。
|
||||
|
||||
73.UnBookmark 从当前选中区中删除全部书签。
|
||||
73.UnBookmark 从当前选中区中删除全部书签。
|
||||
|
||||
74.Underline 切换当前选中区的下划线显示与否。
|
||||
74.Underline 切换当前选中区的下划线显示与否。
|
||||
|
||||
75.Undo 撤消。
|
||||
75.Undo 撤消。
|
||||
|
||||
76.Unlink 从当前选中区中删除全部超级链接。
|
||||
76.Unlink 从当前选中区中删除全部超级链接。
|
||||
|
||||
77.Unselect 清除当前选中区的选中状态。
|
||||
77.Unselect 清除当前选中区的选中状态。
|
||||
```
|
||||
|
||||
|
||||
|
|
@ -3125,7 +3125,7 @@ element.dispatchEvent(event);
|
|||
|
||||
|
||||
|
||||
#### 2.9 Element.scrollIntoView() 让元素滚动到浏览器可视区
|
||||
#### 2.9 Element.scrollIntoView() 让元素滚动到浏览器可视区
|
||||
|
||||
`Element.scrollIntoView`方法**让当前的元素滚动到浏览器窗口的可视区域内** ,类似于设置`window.location.hash`的效果。
|
||||
|
||||
|
|
@ -3350,8 +3350,8 @@ HTML 元素包括标签名和若干个键值对,这个键值对就称为“属
|
|||
NamedNodeMap {0: id, 1: href, id: id, href: href, length: 2}
|
||||
|
||||
// 这两个访问方法都是返回一个id的属性节点对象
|
||||
// NamedNodeMap[0]
|
||||
// NamedNodeMap.id
|
||||
// NamedNodeMap[0]
|
||||
// NamedNodeMap.id
|
||||
|
||||
{
|
||||
baseURI: "file:///C:/Users/dell/Desktop/test.html"
|
||||
|
|
@ -3434,7 +3434,7 @@ HTML 元素的标准属性(即**在标准中定义的属性**),会**自动
|
|||
var a = document.getElementById('test');
|
||||
|
||||
// a是节点对象,id和href自动成为a节点的属性
|
||||
a.id // "aId"
|
||||
a.id // "aId"
|
||||
a.href // "http://www.example.com/"
|
||||
a.className // "aClass"
|
||||
```
|
||||
|
|
@ -3883,7 +3883,7 @@ function reverse(n) {
|
|||
|
||||
## 八、CSS 操作
|
||||
|
||||
CSS 与 JavaScript 是两个有着明确分工的领域,前者负责页面的视觉效果,后者负责与用户的行为互动。但是,它们毕竟同属网页开发的前端,因此不可避免有着交叉和互相配合。本章介绍如何**通过 JavaScript 操作 CSS**。
|
||||
CSS 与 JavaScript 是两个有着明确分工的领域,前者负责页面的视觉效果,后者负责与用户的行为互动。但是,它们毕竟同属网页开发的前端,因此不可避免有着交叉和互相配合。本章介绍如何**通过 JavaScript 操作 CSS**。
|
||||
|
||||
|
||||
|
||||
|
|
@ -4178,7 +4178,7 @@ isPropertySupported('background-clip')
|
|||
`CSS.escape`方法就用来转义那些特殊字符。
|
||||
|
||||
```js
|
||||
document.querySelector('#' + CSS.escape('foo#bar'))
|
||||
document.querySelector('#' + CSS.escape('foo#bar'))
|
||||
//CSS.escape('foo#bar')转义成foo\#bar
|
||||
```
|
||||
|
||||
|
|
@ -4335,14 +4335,14 @@ myStyleSheet instanceof StyleSheet // true
|
|||
|
||||
<script>
|
||||
console.log(document.styleSheets)
|
||||
|
||||
|
||||
/*
|
||||
StyleSheetList {}
|
||||
0: CSSStyleSheet {ownerRule: null, type: "text/css", href: "file:///C:/Users/dell/Desktop/css.css", ownerNode: link, parentStyleSheet: null, …}
|
||||
1: CSSStyleSheet {ownerRule: null, cssRules: CSSRuleList, rules: CSSRuleList, type: "text/css", href: null, …}
|
||||
length: 2
|
||||
*/
|
||||
|
||||
|
||||
console.log(document.styleSheets[0].disabled) // false 未禁用?不能判断样式表设置了alternate?
|
||||
document.styleSheets[0].disabled = true
|
||||
console.log(document.styleSheets[0].disabled) // true 已禁用
|
||||
|
|
@ -4850,17 +4850,17 @@ function mqCallback(e) {
|
|||
|
||||
本章当中的实例(接口)有:
|
||||
|
||||
**CSSStyleDeclaration接口**(css样式声明): 用来操作元素的样式
|
||||
**CSSStyleDeclaration接口**(css样式声明): 用来操作元素的样式
|
||||
|
||||
**StyleSheet接口(样式表**): 代表网页的一张样式表,包括` <link> `元素加载的样式表和` <style> `元素内嵌的样式表。
|
||||
**StyleSheet接口(样式表**): 代表网页的一张样式表,包括` <link> `元素加载的样式表和` <style> `元素内嵌的样式表。
|
||||
|
||||
**CSSRuleList接口(css规则列表)**: 一个类似数组的对象,表示一组 CSS 规则,成员都是 CSSRule 实例。
|
||||
**CSSRuleList接口(css规则列表)**: 一个类似数组的对象,表示一组 CSS 规则,成员都是 CSSRule 实例。
|
||||
|
||||
**CSSRule接口(css规则)**: JavaScript 通过 CSSRule 接口操作 CSS 规则。一般通过 CSSRuleList 接口(`StyleSheet.cssRules`)获取 CSSRule 实例。
|
||||
**CSSRule接口(css规则)**: JavaScript 通过 CSSRule 接口操作 CSS 规则。一般通过 CSSRuleList 接口(`StyleSheet.cssRules`)获取 CSSRule 实例。
|
||||
|
||||
**CSSStyleRule接口**: 如果一条 CSS 规则是普通的样式规则(不含特殊的 CSS 命令),那么除了 CSSRule 接口,它还部署了 CSSStyleRule 接口。
|
||||
**CSSStyleRule接口**: 如果一条 CSS 规则是普通的样式规则(不含特殊的 CSS 命令),那么除了 CSSRule 接口,它还部署了 CSSStyleRule 接口。
|
||||
|
||||
**CSSMediaRule 接口**: 如果一条 CSS 规则是`@media`代码块,那么它除了 CSSRule 接口,还部署了 CSSMediaRule 接口。
|
||||
**CSSMediaRule 接口**: 如果一条 CSS 规则是`@media`代码块,那么它除了 CSSRule 接口,还部署了 CSSMediaRule 接口。
|
||||
|
||||
|
||||
|
||||
|
|
@ -5023,7 +5023,7 @@ mutationObserver.disconnect();
|
|||
下面的例子说明如何读取变动记录。
|
||||
|
||||
```js
|
||||
var callback = function (records){
|
||||
var callback = function (records){
|
||||
console.log(records) // records参数是 MutationRecord实例
|
||||
records.map(function(record){
|
||||
console.log('Mutation type: ' + record.type);
|
||||
|
|
@ -5171,4 +5171,4 @@ ready('.foo', function(element){
|
|||
|
||||
## 文档
|
||||
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
title: 事件
|
||||
date: 2020-01-12 11:49:16
|
||||
permalink: /pages/10b2761db5a8e089
|
||||
categories:
|
||||
categories:
|
||||
- 《JavaScript教程》笔记
|
||||
tags:
|
||||
- null
|
||||
author:
|
||||
tags:
|
||||
- JavaScript
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -16,7 +16,7 @@ author:
|
|||
|
||||
## 一、EventTarget 接口
|
||||
|
||||
事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现。DOM 支持大量的事件,本章开始介绍 **DOM 的事件编程**。
|
||||
事件的本质是程序各个组成部分之间的一种通信方式,也是异步编程的一种实现。DOM 支持大量的事件,本章开始介绍 **DOM 的事件编程**。
|
||||
|
||||
### 1、概述
|
||||
|
||||
|
|
@ -515,7 +515,7 @@ function callback(event) {
|
|||
|
||||
div.addEventListener('click', callback, false); // 该事件是在冒泡阶段监听函数
|
||||
|
||||
var click = new Event('click');
|
||||
var click = new Event('click');
|
||||
p.dispatchEvent(click); // 给p发出一个click事件,该事件默认不会冒泡,因此不会触发父元素div的click事件
|
||||
```
|
||||
|
||||
|
|
@ -703,7 +703,7 @@ document.querySelector('p').onclick = giveDetails;
|
|||
|
||||
### 3、实例方法
|
||||
|
||||
#### 3.1 Event.preventDefault() 取消浏览器对当前事件的默认行为
|
||||
#### 3.1 Event.preventDefault() 取消浏览器对当前事件的默认行为
|
||||
|
||||
`Event.preventDefault`方法**取消浏览器对当前事件的默认行为**。比如点击链接后,浏览器默认会跳转到另一个页面,使用这个方法以后,就不会跳转了;再比如,按一下空格键,页面向下滚动一段距离,使用这个方法以后也不会滚动了。该方法生效的前提是,事件对象的`cancelable`属性为`true`,如果为`false`,调用该方法没有任何效果。
|
||||
|
||||
|
|
@ -1352,7 +1352,7 @@ document.body.addEventListener('keydown', showChar, false);
|
|||
|
||||
- 3:处在数字小键盘。
|
||||
|
||||
|
||||
|
||||
|
||||
#### 3.5 KeyboardEvent.repeat 是否长按
|
||||
|
||||
|
|
@ -1596,7 +1596,7 @@ mySelect.addEventListener('input', inputHandler);
|
|||
var elem = document.getElementById('test');
|
||||
elem.addEventListener('select', function (e) {
|
||||
console.log(e.type); // "select" 事件类型
|
||||
|
||||
|
||||
var _target = e.target;
|
||||
console.log(_target.value); // 文本框的全部值
|
||||
console.log(_target.selectionDirection); // 选择的方向:'forward'正向、'backward'反向
|
||||
|
|
@ -1604,7 +1604,7 @@ elem.addEventListener('select', function (e) {
|
|||
console.log(_target.selectionStart); // 开始选择的索引
|
||||
console.log(_target.selectionEnd); // 结束选择的索引
|
||||
// 注意:开始和结束索引是不分选择方向的,开始的索引一直是靠前的
|
||||
|
||||
|
||||
console.log(_target.value.slice(_target.selectionStart, _target.selectionEnd)) // 选中的那部分字符串
|
||||
}, false);
|
||||
```
|
||||
|
|
@ -1668,7 +1668,7 @@ function changeEventHandler(event) {
|
|||
```html
|
||||
<form onreset="console.log('触发了重置事件')" onsubmit="console.log('触发了提交事件')" name="input" action="html_form_action.php" method="get">
|
||||
<input type="text" name="lname" value="Duck">
|
||||
|
||||
|
||||
<button type="reset">重置</button>
|
||||
<button type="submit">提交</button>
|
||||
</form>
|
||||
|
|
@ -1773,7 +1773,7 @@ TouchEvent {isTrusted: true, touches: TouchList, targetTouches: TouchList, chang
|
|||
length: 1
|
||||
|
||||
__proto__: TouchList
|
||||
|
||||
|
||||
composed: true
|
||||
ctrlKey: false
|
||||
currentTarget: null
|
||||
|
|
@ -2087,7 +2087,7 @@ function handleMove(evt) {
|
|||
|
||||
- `drop`:被拖拉的节点或选中的文本,**释放到目标节点时,在目标节点上触发**。注意,如果当前节点不允许`drop`,即使在该节点上方松开鼠标键,也不会触发该事件。如果用户按下 ESC 键,取消这个操作,也不会触发该事件。该事件的监听函数负责取出拖拉数据,并进行相关处理。
|
||||
|
||||
|
||||
|
||||
|
||||
下面的例子展示,如何动态改变被拖动节点的背景色。
|
||||
|
||||
|
|
@ -2217,7 +2217,7 @@ document.addEventListener('drop', function( event ) {
|
|||
<div ondragover="event.preventDefault()">
|
||||
```
|
||||
|
||||
上面代码中,如果不取消拖拉事件或者阻止默认行为,就不能在`div`节点上放下被拖拉的节点。
|
||||
上面代码中,如果不取消拖拉事件或者阻止默认行为,就不能在`div`节点上放下被拖拉的节点。
|
||||
|
||||
|
||||
|
||||
|
|
@ -3229,4 +3229,4 @@ document.oncontextmenu = function () {// 禁用右键菜单
|
|||
|
||||
## 文档
|
||||
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
|
|
|
|||
|
|
@ -2,11 +2,11 @@
|
|||
title: 浏览器模型
|
||||
date: 2020-01-12 11:49:16
|
||||
permalink: /pages/bab4930124ad2c10
|
||||
categories:
|
||||
categories:
|
||||
- 《JavaScript教程》笔记
|
||||
tags:
|
||||
- null
|
||||
author:
|
||||
tags:
|
||||
- JavaScript
|
||||
author:
|
||||
name: xugaoyi
|
||||
link: https://github.com/xugaoyi
|
||||
---
|
||||
|
|
@ -488,7 +488,7 @@ window.a // 1
|
|||
|
||||
上面代码中,`a`是一个没有声明就直接赋值的变量,它自动成为顶层对象的属性。
|
||||
|
||||
`window`有自己的实体含义,其实不适合当作最高一层的顶层对象,这是一个语言的设计失误。最早,设计这门语言的时候,原始设想是语言内置的对象越少越好,这样可以提高浏览器的性能。因此,语言设计者 Brendan Eich 就把`window`对象当作顶层对象,所有未声明就赋值的变量都自动变成`window`对象的属性。这种设计使得编译阶段无法检测出未声明变量,但到了今天已经没有办法纠正了。
|
||||
`window`有自己的实体含义,其实不适合当作最高一层的顶层对象,这是一个语言的设计失误。最早,设计这门语言的时候,原始设想是语言内置的对象越少越好,这样可以提高浏览器的性能。因此,语言设计者 Brendan Eich 就把`window`对象当作顶层对象,所有未声明就赋值的变量都自动变成`window`对象的属性。这种设计使得编译阶段无法检测出未声明变量,但到了今天已经没有办法纠正了。
|
||||
|
||||
|
||||
|
||||
|
|
@ -738,7 +738,7 @@ window.personalbar.visible
|
|||
|
||||
`window.alert()`、`window.prompt()`、`window.confirm()`都是浏览器与用户互动的全局方法。它们会弹出不同的对话框,要求用户做出回应。注意,这三个方法弹出的对话框,都是浏览器统一规定的式样,无法定制。
|
||||
|
||||
**(1)window.alert() 对话框 **
|
||||
**(1)window.alert() 对话框 **
|
||||
|
||||
`window.alert()`方法**弹出的对话框,只有一个“确定”按钮**,往往用来通知用户某些信息。
|
||||
|
||||
|
|
@ -807,7 +807,7 @@ window.onunload = function () {
|
|||
|
||||
#### 3.2 window.open(), window.close(),window.stop()
|
||||
|
||||
**(1)window.open() 打开一个新窗口**
|
||||
**(1)window.open() 打开一个新窗口**
|
||||
|
||||
`window.open`方法用于**新建另一个浏览器窗口**,类似于浏览器菜单的新建窗口选项。它会返回新窗口的引用,如果无法新建窗口,则返回`null`。
|
||||
|
||||
|
|
@ -1375,11 +1375,11 @@ frames.myframe === myFrame // true
|
|||
|
||||
另外,`name`属性的值会自动成为子窗口的名称,可以用在`window.open`方法的第二个参数,或者` <a> `和` <frame> `标签的`target`属性。
|
||||
|
||||
|
||||
|
||||
|
||||
## 三、Navigator 对象,Screen 对象
|
||||
|
||||
`window.navigator`属性指向一个**包含浏览器和系统信息的 Navigator 对象**。脚本通过这个属性了解用户的环境信息。
|
||||
`window.navigator`属性指向一个**包含浏览器和系统信息的 Navigator 对象**。脚本通过这个属性了解用户的环境信息。
|
||||
|
||||
### 1、Navigator 对象的属性
|
||||
|
||||
|
|
@ -1564,7 +1564,7 @@ if ((screen.width <= 800) && (screen.height <= 600)) {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
|
||||
## 四、Cookie
|
||||
|
||||
|
|
@ -2018,11 +2018,11 @@ xhr.send(null);
|
|||
|
||||
- 0,表示 XMLHttpRequest 实例已经生成,但是实例的`open()`方法还没有被调用。**【生成实例,但没调用open()】**
|
||||
|
||||
|
||||
|
||||
|
||||
- 1,表示`open()`方法已经调用,但是实例的`send()`方法还没有调用,仍然可以使用实例的`setRequestHeader()`方法,设定 HTTP 请求的头信息。**【调用open(),但没调用send()】**
|
||||
|
||||
|
||||
|
||||
|
||||
- 2,表示实例的`send()`方法已经调用,并且服务器返回的头信息和状态码已经收到。**【调用send(),并收到头信息和状态码】**
|
||||
|
||||
|
|
@ -2797,7 +2797,7 @@ function analytics(state) {
|
|||
|
||||
## 六、同源限制
|
||||
|
||||
**浏览器安全的基石是“同源政策”**([same-origin policy](https://en.wikipedia.org/wiki/Same-origin_policy))。很多开发者都知道这一点,但了解得不全面。
|
||||
**浏览器安全的基石是“同源政策”**([same-origin policy](https://en.wikipedia.org/wiki/Same-origin_policy))。很多开发者都知道这一点,但了解得不全面。
|
||||
|
||||
### 1、概述
|
||||
|
||||
|
|
@ -3611,7 +3611,7 @@ function onStorageChange(e) {
|
|||
window.addEventListener('storage', onStorageChange);
|
||||
```
|
||||
|
||||
注意,该事件有一个很特别的地方,就是它不在导致数据变化的当前页面触发,而是在同一个域名的其他窗口触发。也就是说,如果浏览器只打开一个窗口,可能观察不到这个事件。比如同时打开多个窗口,当其中的一个窗口导致储存的数据发生改变时,只有在其他窗口才能观察到监听函数的执行。可以通过这种机制,实现多个窗口之间的通信。
|
||||
注意,该事件有一个很特别的地方,就是它不在导致数据变化的当前页面触发,而是在同一个域名的其他窗口触发。也就是说,如果浏览器只打开一个窗口,可能观察不到这个事件。比如同时打开多个窗口,当其中的一个窗口导致储存的数据发生改变时,只有在其他窗口才能观察到监听函数的执行。可以通过这种机制,实现多个窗口之间的通信。
|
||||
|
||||
|
||||
|
||||
|
|
@ -3793,7 +3793,7 @@ var currentState = history.state;
|
|||
|
||||
## 十、Location 对象,URL 对象,URLSearchParams 对象
|
||||
|
||||
URL 是互联网的基础设施之一。浏览器提供了一些原生对象,用来管理 URL。
|
||||
URL 是互联网的基础设施之一。浏览器提供了一些原生对象,用来管理 URL。
|
||||
|
||||
### 1、Location 对象
|
||||
|
||||
|
|
@ -4407,7 +4407,7 @@ ArrayBuffer 对象表示一段二进制数据,用来模拟内存里面的数
|
|||
浏览器原生提供`ArrayBuffer()`构造函数,用来生成实例。它接受一个整数作为参数,表示这段二进制数据占用多少个字节。
|
||||
|
||||
```js
|
||||
var buffer = new ArrayBuffer(8);
|
||||
var buffer = new ArrayBuffer(8);
|
||||
```
|
||||
|
||||
上面代码中,实例对象`buffer`占用8个字节。
|
||||
|
|
@ -4796,7 +4796,7 @@ function previewFile() {
|
|||
|
||||
|
||||
|
||||
## 十三、表单,FormData 对象
|
||||
## 十三、表单,FormData 对象
|
||||
|
||||
### 1、表单概述
|
||||
|
||||
|
|
@ -6945,4 +6945,4 @@ Worker 线程有一些自己的全局属性和方法。
|
|||
|
||||
## 文档
|
||||
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
学习文档:<https://wangdoc.com/javascript/>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,106 @@
|
|||
---
|
||||
title: JSX简介
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/5df969/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
# 01. JSX简介
|
||||
|
||||
## 什么是JSX?
|
||||
|
||||
```js
|
||||
const element = <h1>Hello, world!</h1>;
|
||||
```
|
||||
|
||||
以类似模板语法的方式描述UI的一种语法。它是JS的**语法糖**,**本质上也是JS**。可以在其中使用**变量或表达式、函数等**。
|
||||
|
||||
|
||||
|
||||
## 为什么使用JSX?
|
||||
|
||||
将*标记与逻辑* 共同存放在称之为“组件”的松散耦合单元之中,来实现[*关注点分离*](https://en.wikipedia.org/wiki/Separation_of_concerns)。
|
||||
|
||||
React不强制使用JSX,但在 JavaScript 代码中将 JSX 和 UI 放在一起时,会在**视觉上有辅助作用**。
|
||||
|
||||
|
||||
|
||||
## 在 JSX 中嵌入表达式
|
||||
|
||||
```js
|
||||
const element = <h1>Hello, {2+2}</h1>;
|
||||
```
|
||||
|
||||
在 JSX 语法中,你可以在大括号内放置任何有效的 [JavaScript 表达式](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Expressions_and_Operators#Expressions)。
|
||||
|
||||
|
||||
|
||||
## JSX 也是一个表达式
|
||||
|
||||
在编译之后,JSX 表达式会被转为普通 JavaScript 函数调用,并且对其取值后**得到 JavaScript 对象**
|
||||
|
||||
> 可以把JSX当初一个对象来对待,可以使用它赋值给变量、当参数输入函数、返回JSX等。
|
||||
|
||||
|
||||
|
||||
## JSX 特定属性
|
||||
|
||||
通过使用引号,来将属性值指定为字符串字面量:
|
||||
|
||||
```js
|
||||
const element = <div tabIndex="0"></div>;
|
||||
```
|
||||
|
||||
> JSX中的属性名使用camelCase(小驼峰)命名。如上面例子中的`tabIndex`
|
||||
|
||||
使用大括号,来在属性值中插入一个 JavaScript 表达式:
|
||||
|
||||
```js
|
||||
const element = <img src={user.avatarUrl}></img>;
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 使用 JSX 指定子元素
|
||||
|
||||
JSX 标签里能够包含很多子元素:
|
||||
|
||||
```jsx
|
||||
const element = (
|
||||
<div>
|
||||
<h1>Hello!</h1>
|
||||
<h2>Good to see you here.</h2>
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## JSX 防止注入攻击
|
||||
|
||||
React DOM 在渲染所有输入内容之前,默认会进行[转义](https://stackoverflow.com/questions/7381974/which-characters-need-to-be-escaped-on-html)。它可以确保在你的应用中,**永远不会注入那些并非自己明确编写的内容**。所有的内容在渲染之前都被转换成了字符串。这样可以有效地防止 [XSS(cross-site-scripting, 跨站脚本)](https://en.wikipedia.org/wiki/Cross-site_scripting)攻击。
|
||||
|
||||
|
||||
|
||||
## JSX 表示对象
|
||||
|
||||
Babel 会把 JSX 转译成一个名为 `React.createElement()` 函数调用。
|
||||
|
||||
以下两种示例代码完全等效:
|
||||
|
||||
```jsx
|
||||
const element = (
|
||||
<h1 className="greeting">
|
||||
Hello, world!
|
||||
</h1>
|
||||
);
|
||||
|
||||
const element = React.createElement(
|
||||
'h1', // 标签名
|
||||
{className: 'greeting'}, // 属性对象
|
||||
'Hello, world!' // 内容
|
||||
);
|
||||
```
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
---
|
||||
title: 元素渲染
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/b5d372/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 02. 元素渲染
|
||||
|
||||
元素是构成 React 应用的最小砖块,描述了你在屏幕上想看到的内容。
|
||||
|
||||
```js
|
||||
const element = <h1>Hello, world</h1>;
|
||||
```
|
||||
|
||||
与浏览器的 DOM 元素不同,**React 元素是创建开销极小的普通对象**。React DOM 会负责更新 DOM 来与 React 元素保持一致。
|
||||
|
||||
## 将一个元素渲染为 DOM
|
||||
|
||||
假设你的 HTML 文件某处有一个 `<div>`:
|
||||
|
||||
```html
|
||||
<div id="root"></div>
|
||||
```
|
||||
|
||||
根节点,React应用只有单一根DOM节点
|
||||
|
||||
> 但一个html页面可以有多个React应用,每个应用对应一个独立根节点。
|
||||
|
||||
```jsx
|
||||
const el = <h1>Hello</h1>
|
||||
ReactDOM.render(el, document.getElementById('root'))
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 更新已渲染的元素
|
||||
|
||||
React 元素是[不可变对象](https://en.wikipedia.org/wiki/Immutable_object)。一旦被创建,你就无法更改它的子元素或者属性。一个元素就像电影的单帧:它代表了某个特定时刻的 UI。
|
||||
|
||||
根据我们已有的知识,更新 UI 唯一的方式是创建一个全新的元素,并将其传入 [`ReactDOM.render()`](https://zh-hans.reactjs.org/docs/react-dom.html#render)。
|
||||
|
||||
考虑一个计时器的例子:
|
||||
|
||||
```jsx
|
||||
function tick() {
|
||||
const element = (
|
||||
<div>
|
||||
<h1>Hello, world!</h1>
|
||||
<h2>It is {new Date().toLocaleTimeString()}.</h2>
|
||||
</div>
|
||||
);
|
||||
ReactDOM.render(element, document.getElementById('root'));}
|
||||
|
||||
setInterval(tick, 1000);
|
||||
```
|
||||
|
||||
注意:在实践中,**大多数 React 应用只会调用一次 [`ReactDOM.render()`](https://zh-hans.reactjs.org/docs/react-dom.html#render)**。在下一个章节,我们将学习如何将这些代码封装到**[有状态组件](https://zh-hans.reactjs.org/docs/state-and-lifecycle.html)**中。
|
||||
|
||||
|
||||
|
||||
## React 只更新它需要更新的部分
|
||||
|
||||
上个例子中,尽管每一秒我们都会新建一个描述整个 UI 树的元素,但React DOM **只会更新实际改变了的内**容。
|
||||
|
|
@ -0,0 +1,203 @@
|
|||
---
|
||||
title: 组件&Props
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/9ac43a/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 03. 组件 & Props
|
||||
|
||||
## 函数组件与 class 组件
|
||||
|
||||
### 1.函数组件
|
||||
|
||||
```jsx
|
||||
function Welcome(props){
|
||||
return <h1>Hello, {props.name}</h1>
|
||||
}
|
||||
```
|
||||
|
||||
该函数是一个有效的React组件。接收唯一带有数据的props参数,并返回一个React元素。
|
||||
|
||||
|
||||
|
||||
### 2.class组件
|
||||
|
||||
使用ES6的class来定义:
|
||||
|
||||
```jsx
|
||||
class Welcome extends React.Component{
|
||||
render() {
|
||||
return <h1>Hello, {this.props.name}</h1>
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
以上两个组件是等效的。
|
||||
|
||||
|
||||
|
||||
## 渲染组件(父子组件传值)
|
||||
|
||||
React 元素也可以是用户自定义的组件:
|
||||
|
||||
```jsx
|
||||
const element = <Welcome name="Sara" />;
|
||||
```
|
||||
|
||||
通过属性(attributes)来传递值给子组件:
|
||||
|
||||
```jsx
|
||||
function Welcome(props) { // 通过props接收传入值
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}
|
||||
|
||||
const element = <Welcome name="Sara" />; // 通过attributes传入值
|
||||
ReactDOM.render(
|
||||
element,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
**注意:** **组件名称必须以大写字母开头。**
|
||||
|
||||
React 会将以小写字母开头的组件视为原生 DOM 标签。例如,`<div />` 代表 HTML 的 div 标签,而 `<Welcome />` 则代表一个组件,并且需在作用域内使用 `Welcome`。
|
||||
|
||||
|
||||
|
||||
## 组合组件(复用组件)
|
||||
|
||||
```jsx
|
||||
function Welcome(props) {
|
||||
return <h1>Hello, {props.name}</h1>;
|
||||
}
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<div>
|
||||
// 复用Welcome组件
|
||||
<Welcome name="Sara" />
|
||||
<Welcome name="Cahal" />
|
||||
<Welcome name="Edite" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<App />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
> 通常来说,每个新的 React 应用程序的顶层组件都是 `App` 组件
|
||||
|
||||
|
||||
|
||||
## 提取组件(拆分组件)
|
||||
|
||||
参考如下 `Comment` 组件:
|
||||
|
||||
```jsx
|
||||
function Comment(props) {
|
||||
return (
|
||||
<div className="Comment">
|
||||
<div className="UserInfo">
|
||||
<img className="Avatar"
|
||||
src={props.author.avatarUrl}
|
||||
alt={props.author.name}
|
||||
/>
|
||||
<div className="UserInfo-name">
|
||||
{props.author.name}
|
||||
</div>
|
||||
</div>
|
||||
<div className="Comment-text">
|
||||
{props.text}
|
||||
</div>
|
||||
<div className="Comment-date">
|
||||
{formatDate(props.date)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
该组件由于嵌套的关系,变得难以维护,且很难复用它的各个部分。因此,让我们从中提取一些组件出来。
|
||||
|
||||
首先,提取 `Avatar` 组件:
|
||||
|
||||
```jsx
|
||||
function Avatar(props) {
|
||||
return (
|
||||
<img className="Avatar"
|
||||
src={props.user.avatarUrl}
|
||||
alt={props.user.name}
|
||||
/>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### props命名原则
|
||||
|
||||
`Avatar` 不需知道它在 `Comment` 组件内部是如何渲染的。因此,我们给它的 props 起了一个更通用的名字:`user`,而不是 `author`。
|
||||
|
||||
我们**建议从组件自身的角度命名 props,而不是依赖于调用组件的上下文命名**。
|
||||
|
||||
|
||||
|
||||
接下来,我们将提取 `UserInfo` 组件,该组件在用户名旁渲染 `Avatar` 组件:
|
||||
|
||||
```jsx
|
||||
function UserInfo(props) {
|
||||
return (
|
||||
<div className="UserInfo">
|
||||
<Avatar user={props.user} />
|
||||
<div className="UserInfo-name">
|
||||
{props.user.name}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
最终的 `Comment` 组件:
|
||||
|
||||
```jsx
|
||||
function Comment(props) {
|
||||
return (
|
||||
<div className="Comment">
|
||||
<UserInfo user={props.author} />
|
||||
<div className="Comment-text">
|
||||
{props.text}
|
||||
</div>
|
||||
<div className="Comment-date">
|
||||
{formatDate(props.date)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
最初看上去,提取组件可能是一件繁重的工作,但是,在大型应用中,构建可复用组件库是完全值得的。
|
||||
|
||||
### 提取原则
|
||||
|
||||
- UI中多次被使用的部分
|
||||
- 一个足够复杂的组件(页面)
|
||||
|
||||
|
||||
|
||||
## Props 的只读性(不能修改Props)
|
||||
|
||||
组件无论是使用[函数声明还是通过 class 声明](https://zh-hans.reactjs.org/docs/components-and-props.html#function-and-class-components),都决不能修改自身的 props。
|
||||
|
||||
> 当然,应用程序的 UI 是动态的,并会伴随着时间的推移而变化。在[下一章节](https://zh-hans.reactjs.org/docs/state-and-lifecycle.html)中,我们将介绍一种新的概念,称之为 “state”。在不违反上述规则的情况下,state 允许 React 组件随用户操作、网络响应或者其他变化而动态更改输出内容
|
||||
|
|
@ -0,0 +1,215 @@
|
|||
---
|
||||
title: State&生命周期
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/1e3ca2/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
# 04. State & 生命周期
|
||||
|
||||
State 与 props 类似,但是 **state 是私有的,并且完全受控于当前组件.**
|
||||
|
||||
> State类似于vue中的data选项
|
||||
|
||||
|
||||
|
||||
## 将函数组件转换成 class 组件
|
||||
|
||||
> 在没有useState钩子函数之前,是通过class组件管理State ?
|
||||
|
||||
```jsx
|
||||
class Clock extends React.Component {
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello, world</h1>
|
||||
<h2>It is {this.props.date.toLocalTimeString()}</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
每次组件更新时 `render` 方法都会被调用,但只要在相同的 DOM 节点中渲染 `<Clock />` ,就**仅有一个 `Clock` 组件的 class 实例被创建使用**。这就使得我们可以使用如 state 或生命周期方法等很多其他特性。
|
||||
|
||||
> 单例模式?
|
||||
|
||||
|
||||
|
||||
## 向 class 组件中添加局部的 state
|
||||
|
||||
```jsx
|
||||
class Clock extends React.Component {
|
||||
// 第二步:添加构造函数,并给 this.state 赋初始值
|
||||
constructor(props) {
|
||||
super(props) // 通过super将props传递到父类构造函数中
|
||||
this.state = {date: new Date()}
|
||||
}
|
||||
render() {
|
||||
// 第一步:render 方法内,将 this.props 替换成 this.state
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello, world</h1>
|
||||
<h2>It is {this.state.date.toLocalTimeString()}</h2>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ReactDOM.render(
|
||||
<Clock />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 将生命周期方法添加到 Class 中
|
||||
|
||||
在具有许多组件的应用程序中,当组件被销毁时释放所占用的资源是非常重要的。
|
||||
|
||||
当 `Clock` 组件第一次被渲染到 DOM 中的时候,就为其[设置一个计时器](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/setInterval)。这在 React 中被称为“**挂载(mount)**”。
|
||||
|
||||
同时,当 DOM 中 `Clock` 组件被删除的时候,应该[清除计时器](https://developer.mozilla.org/en-US/docs/Web/API/WindowTimers/clearInterval)。这在 React 中被称为“**卸载(unmount)**”。
|
||||
|
||||
```jsx
|
||||
class Clock extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {date: new Date()};
|
||||
}
|
||||
|
||||
// 挂载 - 挂载完成后执行
|
||||
componentDidMount() {
|
||||
// 组件挂载后开启定时器
|
||||
this.timerID = serInterval( // 可以向this添加任意属性字段
|
||||
() => this.tick(), 1000
|
||||
)
|
||||
}
|
||||
|
||||
// 卸载
|
||||
componentWillUnmount() {
|
||||
// 组件卸载后清除定时器,释放内存
|
||||
clearInterval(this.timerID)
|
||||
}
|
||||
|
||||
tick() {
|
||||
this.setState({
|
||||
date: new Date()
|
||||
})
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<h1>Hello, world!</h1>
|
||||
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Clock />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 正确地使用 State
|
||||
|
||||
关于 `setState()` 你应该了解三件事:
|
||||
|
||||
### 不要直接修改 State
|
||||
|
||||
```jsx
|
||||
|
||||
// Wrong 不要直接修改state
|
||||
this.state.comment = 'Hello'
|
||||
|
||||
// Correct 应使用 setState() 方法
|
||||
this.setState({comment: 'Hello'})
|
||||
```
|
||||
|
||||
**构造函数是唯一可以给 `this.state` 直接赋值的地方**
|
||||
|
||||
> setState是React内部方法,使state更新具有响应式?
|
||||
|
||||
|
||||
|
||||
### State 的更新可能是异步的
|
||||
|
||||
出于性能考虑,React 可能会把多个 `setState()` 调用合并成一个调用。
|
||||
|
||||
因为 `this.props` 和 `this.state` 可能会异步更新,所以你**不要依赖他们的值来更新下一个状态**。
|
||||
|
||||
要**解决这个问题,可以让 `setState()` 接收一个函数而不是一个对象**。这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数:
|
||||
|
||||
```jsx
|
||||
// Correct
|
||||
this.setState((state, props) => ({
|
||||
counter: state.counter + props.increment
|
||||
}));
|
||||
```
|
||||
|
||||
|
||||
|
||||
### State 的更新会被合并
|
||||
|
||||
当你调用 `setState()` 的时候,React 会把你提供的对象合并到当前的 state
|
||||
|
||||
```jsx
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
posts: [],
|
||||
comments: []
|
||||
};
|
||||
}
|
||||
|
||||
// 分别调用setState单独更新state下的属性
|
||||
componentDidMount() {
|
||||
fetchPosts().then(response => {
|
||||
this.setState({
|
||||
posts: response.posts
|
||||
});
|
||||
});
|
||||
|
||||
fetchComments().then(response => {
|
||||
this.setState({
|
||||
comments: response.comments
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
这里的合并是浅合并,所以 `this.setState({comments})` 完整保留了 `this.state.posts`, 但是完全替换了 `this.state.comments`。
|
||||
|
||||
|
||||
|
||||
## 数据是向下流动的(单向数据流)
|
||||
|
||||
不管是父组件或是子组件都无法知道某个组件是有状态的还是无状态的,并且它们也并不关心它是函数组件还是 class 组件。
|
||||
|
||||
这就是为什么称 **state 为局部的**或是封装的的原因。除了拥有并设置了它的组件,**其他组件都无法访问**。
|
||||
|
||||
组件可以选择把它的 state 作为 props 向下传递到它的子组件中:
|
||||
|
||||
```jsx
|
||||
<FormattedDate date={this.state.date} />
|
||||
```
|
||||
|
||||
`FormattedDate` 组件会在其 props 中接收参数 `date`,但是**组件本身无法知道它是来自于 `Clock` 的 state,或是 `Clock` 的 props,还是手动输入的**。
|
||||
|
||||
|
||||
|
||||
这通常会被叫做“自上而下”或是**“单向”的数据流**。任何的 **state 总是所属于特定的组件**,而且从该 state 派生的任何数据或 UI 只能影响树中“低于”它们的组件。
|
||||
|
||||
如果你把一个以组件构成的树想象成一个 props 的数据瀑布的话,那么每一个组件的 state 就像是在任意一点上给瀑布增加额外的水源,但是它只能向下流动。
|
||||
|
||||
#### 每个组件都是真正独立的。
|
||||
|
|
@ -0,0 +1,162 @@
|
|||
---
|
||||
title: 事件处理
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/f27775/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 05. 事件处理
|
||||
|
||||
## 与传统HTML绑定事件的区别
|
||||
|
||||
传统的 HTML:
|
||||
|
||||
```html
|
||||
<button onclick="activateLasers()">
|
||||
Activate Lasers
|
||||
</button>
|
||||
```
|
||||
|
||||
在 React 中略微不同:
|
||||
|
||||
```jsx
|
||||
// 1.事件名为小驼峰; 2.传入函数以大括号包裹函数名形式
|
||||
<button onClick={activateLasers}>
|
||||
Activate Lasers
|
||||
</button>
|
||||
```
|
||||
|
||||
- React 事件的命名采用小驼峰式(camelCase),而不是纯小写。
|
||||
- 使用 JSX 语法时你需要传入一个函数作为事件处理函数,而不是一个字符串。
|
||||
|
||||
|
||||
|
||||
### 阻止默认事件 (合成事件对象)
|
||||
|
||||
在 React 中,你需要这样阻止默认事件:
|
||||
|
||||
```jsx
|
||||
function ActionLink() {
|
||||
function handleClick(e) {
|
||||
e.preventDefault();
|
||||
console.log('The link was clicked.');
|
||||
}
|
||||
|
||||
return (
|
||||
<a href="#" onClick={handleClick}>
|
||||
Click me
|
||||
</a>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
在这里,`e` 是一个**合成事件**。React 根据 [W3C 规范](https://www.w3.org/TR/DOM-Level-3-Events/)来定义这些合成事件,所以你不需要担心跨浏览器的兼容性问题。React 事件与原生事件不完全相同。如果想了解更多,请查看 [`SyntheticEvent`](https://zh-hans.reactjs.org/docs/events.html) 参考指南。
|
||||
|
||||
|
||||
|
||||
## 绑定事件的方式
|
||||
|
||||
使用 React 时,你一般不需要使用 `addEventListener` 为已创建的 DOM 元素添加监听器。事实上,你只需要在该元素初始渲染的时候添加监听器即可。
|
||||
|
||||
当你使用 [ES6 class](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Classes) 语法定义一个组件的时候,通常的做法是将事件处理函数声明为 class 中的方法。例如,下面的 `Toggle` 组件会渲染一个让用户切换开关状态的按钮:
|
||||
|
||||
```jsx
|
||||
class Toggle extends React.Component {
|
||||
constructor(props){
|
||||
super(props)
|
||||
this.state = {isToggleOn: true};
|
||||
|
||||
// 为了在回调中使用 `this`,这个绑定是必不可少的
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
hadleClick(){
|
||||
this.setState(state => ({
|
||||
isToggleOn: !state.isToggleOn
|
||||
}));
|
||||
}
|
||||
|
||||
render(){
|
||||
return(
|
||||
// 为了能在这里使用 this.handleClick调用方法,因此需要在构造函数内添加handleChick属性指向回调方法 ?
|
||||
<button onClick={this.handleClick}>
|
||||
{this.state.isToggleOn ? 'ON' : 'OFF'}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Toggle />,
|
||||
document.getElementById('root')
|
||||
)
|
||||
```
|
||||
|
||||
你必须谨慎对待 JSX 回调函数中的 `this`,在 JavaScript 中,class 的方法默认不会[绑定](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_objects/Function/bind) `this`。如果你忘记绑定 `this.handleClick` 并把它传入了 `onClick`,当你调用这个函数的时候 `this` 的值为 `undefined`。
|
||||
|
||||
这并不是 React 特有的行为;这其实与 [JavaScript 函数工作原理](https://www.smashingmagazine.com/2014/01/understanding-javascript-function-prototype-bind/)有关。通常情况下,如果你没有在方法后面添加 `()`,例如 `onClick={this.handleClick}`,你应该**为这个方法绑定 `this`**。
|
||||
|
||||
|
||||
|
||||
如果觉得使用 `bind` 很麻烦,这里有两种方式可以解决。如果你正在使用实验性的 [public class fields 语法](https://babeljs.io/docs/plugins/transform-class-properties/),你可以使用 class fields 正确的绑定回调函数:
|
||||
|
||||
```jsx
|
||||
class LoggingButton extends React.Component {
|
||||
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
|
||||
// 注意: 这是 *实验性* 语法。
|
||||
handleClick = () => {
|
||||
console.log('this is:', this);
|
||||
}
|
||||
render() {
|
||||
return (
|
||||
<button onClick={this.handleClick}>
|
||||
Click me
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
[Create React App](https://github.com/facebookincubator/create-react-app) 默认启用此语法。
|
||||
|
||||
|
||||
|
||||
如果你没有使用 class fields 语法,你可以在回调中使用[箭头函数](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions):
|
||||
|
||||
```jsx
|
||||
class LoggingButton extends React.Component {
|
||||
handleClick() {
|
||||
console.log('this is:', this);
|
||||
}
|
||||
|
||||
render() {
|
||||
// 此语法确保 `handleClick` 内的 `this` 已被绑定。
|
||||
return (
|
||||
<button onClick={() => this.handleClick()}>
|
||||
Click me
|
||||
</button>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
此语法问题在于每次渲染 `LoggingButton` 时都会创建不同的回调函数。在大多数情况下,这没什么问题,但如果该回调函数作为 prop 传入子组件时,这些组件可能会进行额外的重新渲染。**我们通常建议在构造器中绑定或使用 class fields 语法来避免这类性能问题**。
|
||||
|
||||
|
||||
|
||||
## 向事件处理程序传递参数
|
||||
|
||||
在循环中,通常我们会为事件处理函数传递额外的参数。例如,若 `id` 是你要删除那一行的 ID,以下两种方式都可以向事件处理函数传递参数:
|
||||
|
||||
```jsx
|
||||
<button onClick={(e) => this.deleteRow(id, e)}>Delete Row</button>
|
||||
<button onClick={this.deleteRow.bind(this, id)}>Delete Row</button>
|
||||
```
|
||||
|
||||
上述两种方式是等价的,分别通过[箭头函数](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)和 [`Function.prototype.bind`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind) 来实现。
|
||||
|
||||
在这两种情况下,**React 的事件对象 `e` 会被作为第二个参数传递**。如果通过箭头函数的方式,事件对象必须显式的进行传递,而通过 `bind` 的方式,事件对象以及更多的参数将会被隐式的进行传递。
|
||||
|
|
@ -0,0 +1,229 @@
|
|||
---
|
||||
title: 条件渲染
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/8fcda8/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 06. 条件渲染
|
||||
|
||||
React 中的条件渲染和 JavaScript 中的一样,使用 JavaScript 运算符 [`if`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) 或者[条件运算符](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Operators/Conditional_Operator)去创建元素来表现当前的状态,然后让 React 根据它们来更新 UI。
|
||||
|
||||
|
||||
|
||||
观察这两个组件:
|
||||
|
||||
```jsx
|
||||
function UserGreeting(props) {
|
||||
return <h1>Welcome back!</h1>;
|
||||
}
|
||||
|
||||
function GuestGreeting(props) {
|
||||
return <h1>Please sign up.</h1>;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
再创建一个 `Greeting` 组件,它会根据用户是否登录来决定显示上面的哪一个组件。
|
||||
|
||||
```jsx
|
||||
function Greeting(props) {
|
||||
const isLoggedIn = props.isLoggedIn;
|
||||
|
||||
// 根据条件来渲染组件(UI)
|
||||
if (isLoggedIn) {
|
||||
return <UserGreeting />;
|
||||
}
|
||||
return <GuestGreeting />;
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
// Try changing to isLoggedIn={true}:
|
||||
<Greeting isLoggedIn={false} />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 元素变量
|
||||
|
||||
你可以使用变量来储存元素。 它可以帮助你有条件地渲染组件的一部分,而其他的渲染部分并不会因此而改变。
|
||||
|
||||
```jsx
|
||||
class LoginControl extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.handleLoginClick = this.handleLoginClick.bind(this);
|
||||
this.handleLogoutClick = this.handleLogoutClick.bind(this);
|
||||
this.state = {isLoggedIn: false};
|
||||
}
|
||||
|
||||
handleLoginClick() {
|
||||
this.setState({isLoggedIn: true});
|
||||
}
|
||||
|
||||
handleLogoutClick() {
|
||||
this.setState({isLoggedIn: false});
|
||||
}
|
||||
|
||||
render() {
|
||||
const isLoggedIn = this.state.isLoggedIn;
|
||||
let button;
|
||||
if (isLoggedIn) {
|
||||
button = <LogoutButton onClick={this.handleLogoutClick} />;
|
||||
} else {
|
||||
button = <LoginButton onClick={this.handleLoginClick} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Greeting isLoggedIn={isLoggedIn} />
|
||||
{button}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<LoginControl />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
[**在 CodePen 上尝试**](https://codepen.io/gaearon/pen/QKzAgB?editors=0010)
|
||||
|
||||
> 此方式有些复杂~
|
||||
|
||||
|
||||
|
||||
## 与运算符 &&
|
||||
|
||||
通过花括号包裹代码,你可以[在 JSX 中嵌入表达式](https://zh-hans.reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx)。这也包括 JavaScript 中的逻辑与 (&&) 运算符。它可以很方便地进行元素的条件渲染:
|
||||
|
||||
```jsx
|
||||
function Mailbox(props){
|
||||
const unreadMeg = props.unreadMeg
|
||||
return (
|
||||
<div>
|
||||
{
|
||||
unreadMeg.length &&
|
||||
<h2>You have {unreadMeg.length} unread messages</h2>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const meg = ['1','22','33']
|
||||
ReactDOM.render(
|
||||
<Mailbox unreadMeg={meg} />,
|
||||
document.getElementById('root')
|
||||
)
|
||||
```
|
||||
|
||||
如果条件是 `true`,`&&` 右侧的元素就会被渲染,如果是 `false`,React 会忽略并跳过它。
|
||||
|
||||
|
||||
|
||||
请**注意**,返回 false 的表达式会使 `&&` 后面的元素被跳过,但会返回 false 表达式。在下面示例中,render 方法的返回值是 `<div>0</div>`。
|
||||
|
||||
```jsx
|
||||
render() {
|
||||
const count = 0;
|
||||
return (
|
||||
<div>
|
||||
// 这里会渲染count的值
|
||||
{ count && <h1>Messages: {count}</h1>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 三目运算符
|
||||
|
||||
```jsx
|
||||
render() {
|
||||
const isLoggedIn = this.state.isLoggedIn;
|
||||
return (
|
||||
<div>
|
||||
The user is <b>{isLoggedIn ? 'currently' : 'not'}</b> logged in.
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
```jsx
|
||||
render() {
|
||||
const isLoggedIn = this.state.isLoggedIn;
|
||||
return (
|
||||
<div>
|
||||
{isLoggedIn
|
||||
? <LogoutButton onClick={this.handleLogoutClick} />
|
||||
: <LoginButton onClick={this.handleLoginClick} />
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
> 可通过三目运算符来条件渲染相应组件。
|
||||
|
||||
|
||||
|
||||
## 阻止组件渲染
|
||||
|
||||
通过让 `render` 方法直接返回 `null`阻止渲染:
|
||||
|
||||
```jsx
|
||||
function WarningBanner(props) {
|
||||
if (!props.warn) {
|
||||
// 返回null则不渲染此组件
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div className="warning">
|
||||
Warning!
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
class Page extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {showWarning: true};
|
||||
this.handleToggleClick = this.handleToggleClick.bind(this);
|
||||
}
|
||||
|
||||
handleToggleClick() {
|
||||
this.setState(state => ({
|
||||
showWarning: !state.showWarning
|
||||
}));
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<WarningBanner warn={this.state.showWarning} />
|
||||
<button onClick={this.handleToggleClick}>
|
||||
{this.state.showWarning ? 'Hide' : 'Show'}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Page />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
在组件的 `render` 方法中返回 `null` 并不会影响组件的生命周期。例如,上面这个示例中,`componentDidUpdate` 依然会被调用。
|
||||
|
|
@ -0,0 +1,220 @@
|
|||
---
|
||||
title: 列表&Key
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/88f4b0/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 07. 列表 & Key
|
||||
|
||||
如下代码,我们使用 [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) 函数让数组中的每一项变双倍,然后我们得到了一个新的列表 `doubled` 并打印出来:
|
||||
|
||||
```js
|
||||
const numbers = [1, 2, 3, 4, 5];
|
||||
const doubled = numbers.map((number) => number * 2);
|
||||
console.log(doubled);
|
||||
```
|
||||
|
||||
在 React 中,把数组转化为[元素](https://zh-hans.reactjs.org/docs/rendering-elements.html)列表的过程是相似的。
|
||||
|
||||
|
||||
|
||||
## 渲染多个组件
|
||||
|
||||
```jsx
|
||||
const numbers = [1,2,3]
|
||||
// 通过map方法将数值放入li,形成一个li标签组成的数值,在一次性放入ul
|
||||
const listItems = numbers.map(number => {
|
||||
<li>{numbers}</li>
|
||||
})
|
||||
|
||||
ReactDOM.render(
|
||||
<ul>{listItems}</ul>
|
||||
document.getElementById('root')
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 基础列表组件
|
||||
|
||||
将列表组合成一个组件:
|
||||
|
||||
```jsx
|
||||
function NumberList(props){
|
||||
const numbers = props.numbers
|
||||
const listItems = numbers.map(number => {
|
||||
// 记得给列表元素添加key
|
||||
<li key={number.toString()}>
|
||||
{number}
|
||||
</li>
|
||||
})
|
||||
|
||||
return (
|
||||
<ul>{listItems}</ul>
|
||||
)
|
||||
}
|
||||
|
||||
const numbers = [1,2,3]
|
||||
ReactDOM.render(
|
||||
<NumberList numbers={numbers} />,
|
||||
document.getElementById('root')
|
||||
)
|
||||
```
|
||||
|
||||
|
||||
|
||||
## key
|
||||
|
||||
**key 帮助 React 识别哪些元素改变了**,比如被添加或删除。因此你应当给数组中的每一个元素赋予一个确定的标识。
|
||||
|
||||
|
||||
|
||||
一个元素的 key 最好是这个元素在列表中拥有的**一个独一无二的字符串**。**通常,我们使用数据中的 id 来作为元素的 key**
|
||||
|
||||
```jsx
|
||||
const todoItems = todos.map((todo) =>
|
||||
<li key={todo.id}>
|
||||
{todo.text}
|
||||
</li>
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
当元素没有确定 id 的时候,**万不得已你可以使用元素索引 index 作为 key**:
|
||||
|
||||
```jsx
|
||||
const todoItems = todos.map((item, index) =>
|
||||
// 只有item中没有id 才用index代替
|
||||
<li key={index}>
|
||||
{item.text}
|
||||
</li>
|
||||
);
|
||||
```
|
||||
|
||||
**如果列表项目的顺序可能会变化,我们不建议使用索引来用作 key 值,因为这样做会导致性能变差,还可能引起组件状态的问题。**
|
||||
|
||||
如果你选择不指定显式的 key 值,那么 React 将默认使用索引用作为列表项目的 key 值
|
||||
|
||||
|
||||
|
||||
## 用 key 提取组件 (在map方法内设置key)
|
||||
|
||||
元素的 key 只有放在就近的数组上下文中才有意义。
|
||||
|
||||
**例子:不正确的使用 key 的方式**
|
||||
|
||||
```jsx
|
||||
function ListItem(props) {
|
||||
const value = props.value;
|
||||
return (
|
||||
// 错误!你不需要在这里指定 key:
|
||||
<li key={value.toString()}>
|
||||
{value}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
function NumberList(props) {
|
||||
const numbers = props.numbers;
|
||||
const listItems = numbers.map((number) =>
|
||||
// 错误!元素的 key 应该在这里指定:
|
||||
<ListItem value={number} />
|
||||
);
|
||||
|
||||
return (
|
||||
<ul>
|
||||
{listItems}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
const numbers = [1, 2, 3, 4, 5];
|
||||
ReactDOM.render(
|
||||
<NumberList numbers={numbers} />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
一个好的经验法则是:**在 `map()` 方法中的元素需要设置 key 属性**。
|
||||
|
||||
##
|
||||
|
||||
## key 只是在兄弟节点之间必须唯一
|
||||
|
||||
数组元素中使用的 key 在其兄弟节点之间应该是独一无二的。然而,它们**不需要是全局唯一的**。当我们生成两个不同的数组时,我们可以使用相同的 key 值。
|
||||
|
||||
```jsx
|
||||
function Blog(props) {
|
||||
const sidebar = ( <ul>
|
||||
{props.posts.map((post) =>
|
||||
<li key={post.id}> {post.title}
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
);
|
||||
const content = props.posts.map((post) => <div key={post.id}> <h3>{post.title}</h3>
|
||||
<p>{post.content}</p>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<div>
|
||||
{sidebar} <hr />
|
||||
{content} </div>
|
||||
);
|
||||
}
|
||||
|
||||
const posts = [
|
||||
{id: 1, title: 'Hello World', content: 'Welcome to learning React!'},
|
||||
{id: 2, title: 'Installation', content: 'You can install React from npm.'}
|
||||
];
|
||||
ReactDOM.render(
|
||||
<Blog posts={posts} />,
|
||||
document.getElementById('root')
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 不能用`key`当props名传给子组件
|
||||
|
||||
key 会传递信息给 React ,但不会传递给你的组件。如果你的组件中需要使用 `key` 属性的值,请用其他属性名显式传递这个值:
|
||||
|
||||
```jsx
|
||||
const content = posts.map((post) =>
|
||||
<Post
|
||||
key={post.id}
|
||||
id={post.id}
|
||||
title={post.title} />
|
||||
);
|
||||
```
|
||||
|
||||
上面例子中,`Post` 组件可以读出 `props.id`,但是**不能读出 `props.key`**。
|
||||
|
||||
## 在 JSX 中嵌入 map()
|
||||
|
||||
JSX 允许在大括号中[嵌入任何表达式](https://zh-hans.reactjs.org/docs/introducing-jsx.html#embedding-expressions-in-jsx),所以我们可以内联 `map()` 返回的结果:
|
||||
|
||||
```jsx
|
||||
function NumberList(props) {
|
||||
const numbers = props.numbers;
|
||||
return (
|
||||
<ul>
|
||||
{
|
||||
numbers.map((number) =>
|
||||
<ListItem key={number.toString()} value={number} />
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
这么做有时可以使你的代码更清晰,但有时这种风格也会被滥用。
|
||||
|
||||
就像在 JavaScript 中一样,何时需要为了可读性提取出一个变量,这完全取决于你。但请记住,如果一个 `map()` 嵌套了太多层级,那可能就是你[提取组件](https://zh-hans.reactjs.org/docs/components-and-props.html#extracting-components)的一个好时机。
|
||||
|
|
@ -0,0 +1,269 @@
|
|||
---
|
||||
title: 表单
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/002db7/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 08. 表单
|
||||
|
||||
## 受控组件(双向数据绑定)
|
||||
|
||||
在 HTML 中,表单元素(如`<input>`、 `<textarea>` 和 `<select>`)通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 [`setState()`](https://zh-hans.reactjs.org/docs/react-component.html#setstate)来更新。
|
||||
|
||||
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。
|
||||
|
||||
例如,如果我们想让前一个示例在提交时打印出名称,我们可以将表单写为受控组件:
|
||||
|
||||
```jsx
|
||||
class Name extends React.Component {
|
||||
constructor(props){
|
||||
super(props);
|
||||
this.state = {value: ''}
|
||||
|
||||
this.handleChange = this.handleChange.bind(this)
|
||||
this.handleSubmit = this.handleSubmit.bind(this)
|
||||
}
|
||||
|
||||
handleChange(event){
|
||||
this.setState({value: event.target.value})
|
||||
}
|
||||
|
||||
handleSubmit(event){
|
||||
alert(this.state.value)
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
render(){
|
||||
return(
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<label>
|
||||
名字:
|
||||
<input type="text" value={this.state.value} onChange={this.handleChange} />
|
||||
</label>
|
||||
<input type="submit" value="提交" />
|
||||
</form>
|
||||
)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
> 类似于vue中的双向绑定,v-model
|
||||
|
||||
|
||||
|
||||
## textarea 标签(使用value定义值)
|
||||
|
||||
在 HTML 中, `<textarea>` 元素通过其子元素定义其文本:
|
||||
|
||||
```html
|
||||
<textarea>
|
||||
你好, 这是在 text area 里的文本
|
||||
</textarea>
|
||||
```
|
||||
|
||||
**在 React 中,`<textarea>` 使用 `value` 属性赋值**。这样,可以使得使用 `<textarea>` 的表单和使用单行 input 的表单非常类似:
|
||||
|
||||
```jsx
|
||||
class EssayForm extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
value: '请撰写一篇关于你喜欢的 DOM 元素的文章.'
|
||||
};
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
handleChange(event) {
|
||||
this.setState({value: event.target.value});
|
||||
}
|
||||
handleSubmit(event) {
|
||||
alert('提交的文章: ' + this.state.value);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<label>
|
||||
文章:
|
||||
<textarea value={this.state.value} onChange={this.handleChange} /> </label>
|
||||
<input type="submit" value="提交" />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**注意,`this.state.value` 初始化于构造函数中,因此文本区域默认有初值**
|
||||
|
||||
|
||||
|
||||
## select 标签 (value代替选中属性)
|
||||
|
||||
**React 在根 `select` 标签上使用 `value` 属性代替`option`元素上的`selected` 属性(选中属性)**
|
||||
|
||||
|
||||
|
||||
在 HTML 中,`<select>` 创建下拉列表标签。例如,如下 HTML 创建了水果相关的下拉列表:
|
||||
|
||||
```jsx
|
||||
<select>
|
||||
<option value="grapefruit">葡萄柚</option>
|
||||
<option value="lime">酸橙</option>
|
||||
<option selected value="coconut">椰子</option>
|
||||
<option value="mango">芒果</option>
|
||||
</select>
|
||||
```
|
||||
|
||||
请注意,由于 `selected` 属性的缘故,椰子选项默认被选中。**React 并不会使用 `selected` 属性,而是在根 `select` 标签上使用 `value` 属性**。这在受控组件中更便捷,因为您只需要在根标签中更新它。例如:
|
||||
|
||||
```jsx
|
||||
class FlavorForm extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {value: 'coconut'};
|
||||
|
||||
this.handleChange = this.handleChange.bind(this);
|
||||
this.handleSubmit = this.handleSubmit.bind(this);
|
||||
}
|
||||
|
||||
handleChange(event) {
|
||||
this.setState({value: event.target.value});
|
||||
}
|
||||
|
||||
handleSubmit(event) {
|
||||
alert('你喜欢的风味是: ' + this.state.value);
|
||||
event.preventDefault();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form onSubmit={this.handleSubmit}>
|
||||
<label>
|
||||
选择你喜欢的风味:
|
||||
<select value={this.state.value} onChange={this.handleChange}>
|
||||
<option value="grapefruit">葡萄柚</option>
|
||||
<option value="lime">酸橙</option>
|
||||
<option value="coconut">椰子</option>
|
||||
<option value="mango">芒果</option>
|
||||
</select>
|
||||
</label>
|
||||
<input type="submit" value="提交" />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### select多选
|
||||
|
||||
你可以将数组传递到 `value` 属性中,以支持在 `select` 标签中选择多个选项:
|
||||
|
||||
```jsx
|
||||
<select multiple={true} value={['B', 'C']}>
|
||||
```
|
||||
|
||||
### 小总结
|
||||
|
||||
总的来说,这使得 `<input type="text">`, `<textarea>` 和 `<select>` 之类的标签都非常相似—它们都接受一个 `value` 属性,你可以使用它来实现受控组件。
|
||||
|
||||
|
||||
|
||||
## 文件 input 标签 (非受控组件)
|
||||
|
||||
在 HTML 中,`<input type="file">` 允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用 JavaScript 的 [File API](https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications) 进行控制。
|
||||
|
||||
```html
|
||||
<input type="file" />
|
||||
```
|
||||
|
||||
因为它的 value 只读,所以它是 React 中的一个**非受控**组件。将与其他非受控组件[在后续文档中](https://zh-hans.reactjs.org/docs/uncontrolled-components.html#the-file-input-tag)一起讨论。
|
||||
|
||||
|
||||
|
||||
## 处理多个输入
|
||||
|
||||
当需要处理多个 `input` 元素时,我们可以给每个元素添加 `name` 属性,并让处理函数根据 `event.target.name` 的值选择要执行的操作。
|
||||
|
||||
```jsx
|
||||
class Reservation extends React.Component {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
isGoing: true,
|
||||
numberOfGuests: 2
|
||||
};
|
||||
|
||||
this.handleInputChange = this.handleInputChange.bind(this);
|
||||
}
|
||||
|
||||
handleInputChange(event) {
|
||||
const target = event.target;
|
||||
const value = target.type === 'checkbox' ? target.checked : target.value;
|
||||
const name = target.name;
|
||||
|
||||
this.setState({
|
||||
// ES6 计算属性名称
|
||||
[name]: value
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<form>
|
||||
<label>
|
||||
参与:
|
||||
<input
|
||||
name="isGoing"
|
||||
type="checkbox"
|
||||
checked={this.state.isGoing}
|
||||
onChange={this.handleInputChange} />
|
||||
</label>
|
||||
<br />
|
||||
<label>
|
||||
来宾人数:
|
||||
<input
|
||||
name="numberOfGuests"
|
||||
type="number"
|
||||
value={this.state.numberOfGuests}
|
||||
onChange={this.handleInputChange} />
|
||||
</label>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 受控输入空值
|
||||
|
||||
在[受控组件](https://zh-hans.reactjs.org/docs/forms.html#controlled-components)上指定 value 的 prop 会阻止用户更改输入。如果你指定了 `value`,但输入仍可编辑,则可能是你意外地将`value` 设置为 `undefined` 或 `null`。
|
||||
|
||||
下面的代码演示了这一点。(输入最初被锁定,但在短时间延迟后变为可编辑。)
|
||||
|
||||
```jsx
|
||||
ReactDOM.render(<input value="hi" />, mountNode);
|
||||
|
||||
setTimeout(function() {
|
||||
ReactDOM.render(<input value={null} />, mountNode);
|
||||
}, 1000);
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 受控组件的替代品 (非受控组件)
|
||||
|
||||
有时使用受控组件会很麻烦,因为**你需要为数据变化的每种方式都编写事件处理函数,并通过一个 React 组件传递所有的输入 state**。当你将之前的代码库转换为 React 或将 React 应用程序与非 React 库集成时,这可能会令人厌烦。在这些情况下,你可能希望使用[非受控组件](https://zh-hans.reactjs.org/docs/uncontrolled-components.html), 这是实现输入表单的另一种方式。
|
||||
|
||||
|
||||
|
||||
## 成熟的解决方案
|
||||
|
||||
如果你想寻找包含验证、追踪访问字段以及处理表单提交的完整解决方案,使用 [Formik](https://jaredpalmer.com/formik) 是不错的选择。然而,它也是建立在受控组件和管理 state 的基础之上 —— 所以不要忽视学习它们。
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: 状态提升
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/f0e3d2/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 09. 状态提升
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: 组合vs继承
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/9ae8e8/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 10.组合vs继承
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
title: React哲学
|
||||
date: 2021-03-24 17:56:40
|
||||
permalink: /pages/c689bf/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 核心概念
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
|
||||
# 11.React哲学
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: 高级指引
|
||||
date: 2021-03-25 19:46:01
|
||||
permalink: /pages/b7ec27/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- 高级指引
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
# 01.高级指引
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
title: Hook
|
||||
date: 2021-03-25 19:46:03
|
||||
permalink: /pages/4c13b9/
|
||||
categories:
|
||||
- 《React》笔记
|
||||
- Hook
|
||||
tags:
|
||||
- React
|
||||
---
|
||||
# 01. Hook
|
||||
|
|
@ -3,11 +3,11 @@ title: 简介
|
|||
date: 2020-01-05 10:15:07
|
||||
permalink: /pages/e05dce83e5129785
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- 初识 TypeScript
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 简介
|
||||
|
||||
|
|
@ -36,5 +36,3 @@ TypeScript 提供最新的和不断发展的 JavaScript 特性,包括那些来
|
|||
## 总结
|
||||
|
||||
TypeScript 在社区的流行度越来越高,它非常适用于一些大型项目,也非常适用于一些基础库,极大地帮助我们提升了开发效率和体验。如果你还没有开始学习 TypeScript,那么你可能要落后了哟,所以还等什么,快来和我一起学习并使用 TypeScript 吧,来感受一下它为我们带来的奇妙体验。
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 安装 TypeScript
|
|||
date: 2020-01-05 10:15:07
|
||||
permalink: /pages/064e0f7b6b6142c8
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- 初识 TypeScript
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 安装 TypeScript
|
||||
|
||||
|
|
@ -20,5 +20,5 @@ npm install -g typescript
|
|||
安装完成后,在控制台运行如下命令,检查安装是否成功(3.x):
|
||||
|
||||
```bash
|
||||
tsc -V
|
||||
tsc -V
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 编写第一个 TypeScript 程序
|
|||
date: 2020-01-05 10:15:07
|
||||
permalink: /pages/c85249f40e7a3517
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- 初识 TypeScript
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 编写第一个 TypeScript 程序
|
||||
|
||||
|
|
@ -146,7 +146,3 @@ console.log(greeter(user))
|
|||
## 总结
|
||||
|
||||
到这里,你已经对 TypeScript 有了一个大致的印象,那么下一章让我们来一起学习 TypeScript 的一些常用语法吧。
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 基础类型
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/28672e2743bbc3a7
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 基础类型
|
||||
|
||||
|
|
@ -250,7 +250,3 @@ let strLength: number = (someValue as string).length
|
|||
```
|
||||
|
||||
两种形式是等价的。 至于使用哪个大多数情况下是凭个人喜好;然而,当你在 TypeScript 里使用 JSX 时,只有 `as` 语法断言是被允许的。
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 变量声明
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/54add7f5cf78088e
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 变量声明
|
||||
|
||||
|
|
@ -84,7 +84,7 @@ function sumMatrix(matrix) {
|
|||
sum += currentRow[i]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return sum
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 接口
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/54ea89b497ec3bb3
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 接口
|
||||
|
||||
|
|
@ -90,7 +90,7 @@ interface SquareConfig {
|
|||
color?: string;
|
||||
width?: number;
|
||||
}
|
||||
|
||||
|
||||
function createSquare(config: SquareConfig): Square {
|
||||
let newSquare = {color: 'white', area: 100}
|
||||
if (config.clor) {
|
||||
|
|
@ -102,7 +102,7 @@ function createSquare(config: SquareConfig): Square {
|
|||
}
|
||||
return newSquare
|
||||
}
|
||||
|
||||
|
||||
let mySquare = createSquare({color: 'black'})
|
||||
```
|
||||
|
||||
|
|
@ -493,4 +493,3 @@ class ImageC implements SelectableControl {
|
|||
在上面的例子里,`SelectableControl` 包含了 `Control` 的所有成员,包括私有成员 `state`。 因为 `state` 是私有成员,所以只能够是 `Control` 的子类们才能实现 `SelectableControl` 接口。 因为只有 `Control` 的子类才能够拥有一个声明于`Control` 的私有成员 `state`,这对私有成员的兼容性是必需的。
|
||||
|
||||
在 `Control` 类内部,是允许通过 `SelectableControl` 的实例来访问私有成员 `state` 的。 实际上,`SelectableControl` 接口和拥有 `select` 方法的 `Control` 类是一样的。`Button`和 `TextBox` 类是 `SelectableControl` 的子类(因为它们都继承自`Control` 并有 `select` 方法),但 `ImageC` 类并不是这样的。
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 类
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/fad060bd9a8bfac6
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 类
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ dog.move(10)
|
|||
```typescript
|
||||
class Animal {
|
||||
name: string
|
||||
constructor(name: string) {
|
||||
constructor(name: string) {
|
||||
this.name = name
|
||||
}
|
||||
move(distance: number = 0) {
|
||||
|
|
@ -79,7 +79,7 @@ class Animal {
|
|||
}
|
||||
|
||||
class Snake extends Animal {
|
||||
constructor(name: string) {
|
||||
constructor(name: string) {
|
||||
super(name)
|
||||
}
|
||||
move(distance: number = 5) {
|
||||
|
|
@ -145,7 +145,7 @@ class Animal {
|
|||
```typescript
|
||||
class Animal {
|
||||
private name: string
|
||||
constructor(name: string) {
|
||||
constructor(name: string) {
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
|
|
@ -162,20 +162,20 @@ TypeScript 使用的是结构性类型系统。 当我们比较两种不同的
|
|||
```typescript
|
||||
class Animal {
|
||||
private name: string
|
||||
constructor(name: string) {
|
||||
this.name = name
|
||||
constructor(name: string) {
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
|
||||
class Rhino extends Animal {
|
||||
constructor() {
|
||||
constructor() {
|
||||
super('Rhino')
|
||||
}
|
||||
}
|
||||
|
||||
class Employee {
|
||||
private name: string
|
||||
constructor(name: string) {
|
||||
constructor(name: string) {
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
|
|
@ -197,8 +197,8 @@ animal = employee // 错误: Animal 与 Employee 不兼容.
|
|||
```typescript
|
||||
class Person {
|
||||
protected name: string
|
||||
constructor(name: string) {
|
||||
this.name = name
|
||||
constructor(name: string) {
|
||||
this.name = name
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +209,7 @@ class Employee extends Person {
|
|||
super(name)
|
||||
this.department = department
|
||||
}
|
||||
|
||||
|
||||
getElevatorPitch() {
|
||||
return `Hello, my name is ${this.name} and I work in ${this.department}.`
|
||||
}
|
||||
|
|
@ -466,7 +466,7 @@ console.log(greeter.greet());
|
|||
```typescript
|
||||
class Greeter {
|
||||
static standardGreeting = 'Hello, there'
|
||||
|
||||
|
||||
greeting: string
|
||||
|
||||
constructor(message?: string) {
|
||||
|
|
@ -513,5 +513,3 @@ interface Point3d extends Point {
|
|||
|
||||
let point3d: Point3d = {x: 1, y: 2, z: 3}
|
||||
```
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 函数
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/870a51ba2a9edfad
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 函数
|
||||
|
||||
|
|
@ -26,7 +26,7 @@ function add(x, y) {
|
|||
}
|
||||
|
||||
// 匿名函数
|
||||
let myAdd = function(x, y) {
|
||||
let myAdd = function(x, y) {
|
||||
return x + y;
|
||||
}
|
||||
```
|
||||
|
|
@ -52,7 +52,7 @@ function add(x: number, y: number): number {
|
|||
return x + y
|
||||
}
|
||||
|
||||
let myAdd = function(x: number, y: number): number {
|
||||
let myAdd = function(x: number, y: number): number {
|
||||
return x + y
|
||||
}
|
||||
```
|
||||
|
|
@ -64,7 +64,7 @@ let myAdd = function(x: number, y: number): number {
|
|||
现在我们已经为函数指定了类型,下面让我们写出函数的完整类型。
|
||||
|
||||
```typescript
|
||||
let myAdd: (x: number, y: number) => number =
|
||||
let myAdd: (x: number, y: number) => number =
|
||||
function(x: number, y: number): number {
|
||||
return x + y
|
||||
}
|
||||
|
|
@ -74,7 +74,7 @@ function(x: number, y: number): number {
|
|||
函数类型包含两部分:参数类型和返回值类型。 当写出完整函数类型的时候,这两部分都是需要的。 我们以参数列表的形式写出参数类型,为每个参数指定一个名字和类型。这个名字只是为了增加可读性。 我们也可以这么写:
|
||||
|
||||
```typescript
|
||||
let myAdd: (baseValue: number, increment: number) => number =
|
||||
let myAdd: (baseValue: number, increment: number) => number =
|
||||
function(x: number, y: number): number {
|
||||
return x + y
|
||||
}
|
||||
|
|
@ -91,11 +91,11 @@ function(x: number, y: number): number {
|
|||
尝试这个例子的时候,你会发现如果你在赋值语句的一边指定了类型但是另一边没有类型的话,TypeScript 编译器会自动识别出类型:
|
||||
|
||||
```typescript
|
||||
let myAdd = function(x: number, y: number): number {
|
||||
let myAdd = function(x: number, y: number): number {
|
||||
return x + y
|
||||
}
|
||||
|
||||
let myAdd: (baseValue: number, increment: number) => number =
|
||||
let myAdd: (baseValue: number, increment: number) => number =
|
||||
function(x, y) {
|
||||
return x + y
|
||||
}
|
||||
|
|
@ -322,7 +322,7 @@ let uiElement: UIElement = {
|
|||
uiElement.addClickListener(h.onClickBad) // error!
|
||||
|
||||
```
|
||||
|
||||
|
||||
指定了 `this` 类型后,你显式声明 `onClickBad` 必须在 `Handler` 的实例上调用。 然后 TypeScript 会检测到 `addClickListener` 要求函数带有 `this: void`。 改变 `this` 类型来修复这个错误:
|
||||
|
||||
```typescript
|
||||
|
|
@ -350,7 +350,7 @@ uiElement.addClickListener(h.onClickBad)
|
|||
class Handler {
|
||||
type: string
|
||||
onClickGood = (e: Event) => {
|
||||
this.type = e.type
|
||||
this.type = e.type
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 泛型
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/8045759ec4ad3c01
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 泛型
|
||||
|
||||
|
|
@ -180,7 +180,7 @@ class GenericNumber<T> {
|
|||
let myGenericNumber = new GenericNumber<number>()
|
||||
myGenericNumber.zeroValue = 0
|
||||
myGenericNumber.add = function(x, y) {
|
||||
return x + y
|
||||
return x + y
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -189,7 +189,7 @@ myGenericNumber.add = function(x, y) {
|
|||
```typescript
|
||||
let stringNumeric = new GenericNumber<string>()
|
||||
stringNumeric.zeroValue = ''
|
||||
stringNumeric.add = function(x, y) {
|
||||
stringNumeric.add = function(x, y) {
|
||||
return x + y
|
||||
}
|
||||
|
||||
|
|
@ -252,4 +252,3 @@ let x = {a: 1, b: 2, c: 3, d: 4}
|
|||
getProperty(x, 'a') // okay
|
||||
getProperty(x, 'm') // error
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 类型推断
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/7279420c899c505d
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 类型推断
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 高级类型
|
|||
date: 2020-01-05 10:17:47
|
||||
permalink: /pages/3fb6c2f52ab398e3
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- TypeScript 常用语法
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 高级类型
|
||||
|
||||
|
|
@ -377,6 +377,3 @@ Argument of type '"uneasy"' is not assignable to parameter of type '"ease-in" |
|
|||
那么到这里,我们的 TypeScript 常用语法学习就告一段落了,当然 TypeScript 还有其他的语法我们并没有讲,我们只是讲了 TypeScript 的一些常用语法,你们把这些知识学会已经足以开发一般的应用了。如果你在使用 TypeScript 开发项目中遇到了其他的 TypeScript 语法知识,你可以通过 TypeScript 的[官网文档](https://www.typescriptlang.org/docs/home.html)学习。因为学基础最好的方法还是去阅读它的官网文档,敲上面的小例子。其实我们课程的基础知识结构也是大部分参考了官网文档,要记住学习一门技术的基础官网文档永远是最好的第一手资料。
|
||||
|
||||
但是 TypeScript 的学习不能仅仅靠看官网文档,你还需要动手实践,在实践中你才能真正掌握 TypeScript。相信很多同学学习到这里已经迫不及待想要大展身手了,那么下面我们就开始把理论转换为实践,一起来用 TypeScript 重构 axios 吧!
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 需求分析
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/195af93fcc871b8b
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 项目初始化
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 需求分析
|
||||
|
||||
|
|
@ -26,4 +26,3 @@ tags:
|
|||
此外,我们还会支持一些 axios 库支持的一些其它的 feature。这里要注意的,我们这次重构不包括 axios 在 Node 中的实现,因为这部分我们在平时项目中应用的很少,还涉及到很多 Node.js 的知识,如果都讲的话,一是比较占用时间,另一个可能会喧宾夺主了。当然,这部分知识点我会根据同学们学习的反馈,如果大家很感兴趣想学习的话,我就作为课程的补充内容加到后期视频的扩展中,也当做课程的福利送给大家,所以大家务必要支持一下正版课程喔~
|
||||
|
||||
那么接下来我们就开始初始化项目吧!
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 初始化项目
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/6e11ac76475a2b3e
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 项目初始化
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 初始化项目
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ npm install
|
|||
|
||||
```
|
||||
├── CONTRIBUTING.md
|
||||
├── LICENSE
|
||||
├── LICENSE
|
||||
├── README.md
|
||||
├── code-of-conduct.md
|
||||
├── node_modules
|
||||
|
|
@ -83,11 +83,11 @@ npm install
|
|||
- `npm test`: 运行 `jest` 工具跑单元测试。
|
||||
- `npm run commit`: 运行 `commitizen` 工具提交格式化的 `git commit` 注释。
|
||||
- `npm run build`: 运行 `rollup` 编译打包 TypeScript 代码,并运行 `typedoc` 工具生成文档。
|
||||
|
||||
|
||||
## 关联远程分支
|
||||
|
||||
|
||||
代码已经初始化好,接下来我们要把当前代码仓库关联我们的远程仓库,首先在命令行中运行命令查看远程分支:
|
||||
|
||||
|
||||
```bash
|
||||
git remote -v
|
||||
```
|
||||
|
|
@ -125,9 +125,9 @@ Aborting
|
|||
git pull origin master
|
||||
```
|
||||
|
||||
这次代码就拉取成功了,并且在本地也创建了一个 `master` 分支。
|
||||
这次代码就拉取成功了,并且在本地也创建了一个 `master` 分支。
|
||||
|
||||
|
||||
|
||||
### 提交代码
|
||||
|
||||
最后我们来提交代码,首先运行:
|
||||
|
|
@ -146,5 +146,3 @@ git push origin master
|
|||
接着我们去 GitHub 仓库中就可以看到刚才这条提交记录了。
|
||||
|
||||
至此,我们项目已经初始化完毕,接下来我们就开始编写源码实现 axios 了。
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 编写基础请求代码
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/acfe1e0b401fa984
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 项目初始化
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 编写基础请求代码
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 处理请求 url 参数
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/1313dae575f6dddf
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 基础功能实现
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 处理请求 url 参数
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 处理请求 body 数据
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/887cd0918e2543d8
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 基础功能实现
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 处理请求 body 数据
|
||||
|
||||
|
|
@ -23,9 +23,9 @@ tags:
|
|||
axios({
|
||||
method: 'post',
|
||||
url: '/base/post',
|
||||
data: {
|
||||
data: {
|
||||
a: 1,
|
||||
b: 2
|
||||
b: 2
|
||||
}
|
||||
})
|
||||
```
|
||||
|
|
@ -152,5 +152,3 @@ router.post('/base/buffer', function(req, res) {
|
|||
实际上是因为我们虽然执行 `send` 方法的时候把普通对象 `data` 转换成一个 `JSON` 字符串,但是我们请求`header` 的 `Content-Type` 是 `text/plain;charset=UTF-8`,导致了服务端接受到请求并不能正确解析请求 `body` 的数据。
|
||||
|
||||
知道这个问题后,下面一节课我们来实现对请求 `header` 的处理。
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 处理请求 header
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/35c0ec1bb0b0faaf
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 基础功能实现
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 处理请求 header
|
||||
|
||||
|
|
@ -70,7 +70,7 @@ function normalizeHeaderName (headers: any, normalizedName: string): void {
|
|||
|
||||
export function processHeaders (headers: any, data: any): any {
|
||||
normalizeHeaderName(headers, 'Content-Type')
|
||||
|
||||
|
||||
if (isPlainObject(data)) {
|
||||
if (headers && !headers['Content-Type']) {
|
||||
headers['Content-Type'] = 'application/json;charset=utf-8'
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 获取响应数据
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/a57debe141e1e4f4
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 基础功能实现
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 获取响应数据
|
||||
|
||||
|
|
@ -162,5 +162,3 @@ axios({
|
|||
我们打开浏览器运行 demo,看一下结果,发现我们可以正常 log 出这个 `res` 变量,它包含 `AxiosResponse` 类型中定义的那些属性,不过我们发现 2 个小问题:第一个是 `headers` 属性是一个字符串,我们需要把它解析成对象类型;第二个是在第一个请求中,得到的数据是一个 JSON 字符串,我们也需要把它转换成对象类型。
|
||||
|
||||
那么下一小节,我们将来解决第一个问题,对于响应的 `header` 做处理。
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 处理响应 header
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/927161662ca32c24
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 基础功能实现
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 处理响应 header
|
||||
|
||||
|
|
@ -73,4 +73,4 @@ export function parseHeaders(headers: string): any {
|
|||
const responseHeaders = parseHeaders(request.getAllResponseHeaders())
|
||||
```
|
||||
|
||||
接着我们再去看刚才的 demo,发现我们已经把响应的 `headers` 字段从字符串解析成对象结构了。那么接下来,我们在解决之前遗留的第二个问题:对响应 `data` 字段的处理。
|
||||
接着我们再去看刚才的 demo,发现我们已经把响应的 `headers` 字段从字符串解析成对象结构了。那么接下来,我们在解决之前遗留的第二个问题:对响应 `data` 字段的处理。
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 处理响应 data
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/922cb4268499dc3f
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 基础功能实现
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 处理响应 data
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 错误处理
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/6a8bef7b98dfdcf9
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 异常情况处理
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 错误处理
|
||||
|
||||
|
|
@ -199,4 +199,4 @@ router.get('/error/timeout', function(req, res) {
|
|||
|
||||
然后在命令行运行 `npm run dev`,接着打开 chrome 浏览器,访问 `http://localhost:8080/` 即可访问我们的 demo 了,我们点到 `Error` 目录下,通过开发者工具的 network 部分我们可以看到不同的错误情况。
|
||||
|
||||
至此我们对各种错误都做了处理,并把它们抛给了程序应用方,让他们对错误可以做进一步的处理。但是这里我们的错误都仅仅是简单的 Error 实例,只有错误文本信息,并不包含是哪个请求、请求的配置、响应对象等其它信息。那么下一节课,我们会对错误信息做增强。
|
||||
至此我们对各种错误都做了处理,并把它们抛给了程序应用方,让他们对错误可以做进一步的处理。但是这里我们的错误都仅仅是简单的 Error 实例,只有错误文本信息,并不包含是哪个请求、请求的配置、响应对象等其它信息。那么下一节课,我们会对错误信息做增强。
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 错误信息增强
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/22d581d8c2860b8a
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 异常情况处理
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 错误信息增强
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 扩展接口
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/034e320f4af88bd4
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 接口扩展
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 扩展接口
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: axios 函数重载
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/8af227eae851ec97
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 接口扩展
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# axios 函数重载
|
||||
|
||||
|
|
@ -72,7 +72,7 @@ export interface AxiosInstance extends Axios {
|
|||
}
|
||||
return dispatchRequest(config)
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
我们把 `request` 函数的参数改成 2 个,`url` 和 `config` 都是 `any` 类型,`config` 还是可选参数。
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,11 @@ title: 响应数据支持泛型
|
|||
date: 2020-01-05 10:56:02
|
||||
permalink: /pages/c4489d0bab02cc0c
|
||||
author: HuangYi
|
||||
categories:
|
||||
categories:
|
||||
- 《TypeScript 从零实现 axios》
|
||||
- ts-axios 接口扩展
|
||||
tags:
|
||||
-
|
||||
tags:
|
||||
- TypeScript
|
||||
---
|
||||
# 响应数据支持泛型
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue