上一章:css预处理器
1. 了解ES5.1
- 文档:https://www.w3cschool.cn/kesyi/kesyi-nqej24rv.html
- ECMAScript其实是指一种规范,或者说是一个标准。具体点来说,它其实就是一份文档(ECMA-262)
- ES5的最后版本是ES5.1, 在ES5.1中提出了一些新的特性
- Strict Mode(严格模式)
- JSON对象
- Object扩展
- Array扩展
- Function.prototype.bind
2. 严格模式(了解)
理解
- 文档: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Strict_mode
- 默认使用非严格模式/常规模式(sloppy mode),ES5.1添加了第二种运行模式:“严格模式”(strict mode)
- 顾名思义,这种模式使得Javascript在更严格的语法条件下运行
作用
- 严格模式修复了一些导致 JavaScript引擎难以执行优化的缺陷
- 消除代码运行的一些不安全之处,为代码的安全运行保驾护航
- 为未来新版本的JavaScript做好铺垫
开启严格模式
- 写法一: 在全局第一行指定为: ‘use strict’, ==> 所有代码都以严格模式运行
- 写法二: 在函数体的第一行指定为: ‘use strict’ ==> 仅当前函数以严格模式运行。
- 如果浏览器不支持, 只解析为一条简单的语句, 没有任何副作用
有哪些变化?
编码 | 非严格模式 | 严格模式 |
---|---|---|
给未声明的变量赋值 | 自动创建全局变量 | 报错(未定义) |
函数中的this | 可以指向window | 不能指向window, 而是undefined |
同名形参 | 允许 | 不允许 |
… | … | … |
/*
ES5默认是非严格模式
开启严格模式: 'use strict'
严格模式的变化:
| 编码 | 非严格模式 | 严格模式 |
| 给未声明的变量赋值 | 自动创建全局变量 | 报错(未定义) |
| 函数中的this | 可以指向window | 不能指向window, 而是undefined |
| 同名形参 | 允许 | 不允许 |
*/
'use strict'
/* | 给未声明的变量赋值 | 自动创建全局变量 | 报错(未定义) | */
// a = 2
// function fn() {
// b = 3
// }
// fn()
// console.log(a, b)
/* | 函数中的this | 可以指向window | 不能指向window, 而是undefined | */
// function fn() {
// console.log(this)
// }
// fn()
/* | 同名形参 | 允许 | 不允许 | */
// function fn(a, a) {
// console.log(a)
// }
// fn(1, 2)
// delete Object.prototype
面试题
- 说出几个严格模式的语法特性变化
3. JSON与JSON对象(重要)
JSON
-
https://baike.baidu.com/item/JSON/2462549?fr=aladdin
-
JSON全称 JavaScript Object Notation,是一种轻量级的通用的数据交换格式, 专门用来存储结构化的文本数据
- json对象: {key1: value1, key2: value2}
- json数组: [value1, value2]
- key只能是string
- value可以是: string / number / boolean / null / {} / []
- 特别注意: json中的string只能用双引号, 不能用单引号
-
应用JSON的场景?
- 存储JSON数据的文件 ==> JSON文件 ==> xxx.json
- 前后台交互传输文本数据 ==> JSON文本(也就是json字符串)
-
JSON 与 JS 对象的关系
- JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串
-
以前存储或传输结构化的数据都是用XML格式, 现在更多的是用json格式
-
json更小
-
解析和生成更快
/* 需求: 存储2个人的信息: jack/18岁/喜欢football&basketball&pingpang tom/21岁/喜欢pingpang */ data.xml <students> <student> <name>tom</name> <age>18</age> <likes> <like>football</like> <like>basketball</like> <like>pingpang</like> </likes> </student> <student> <name>jack</name> <age>21</age> <likes> <like>pingpang</like> </likes> </student> </students> data.json [ { "name": "tom", "age": 18, "likes": ["football", "basketball", "pingpang"] }, { "name": "jack", "age": 21, "likes": ["pingpang"] } ]
/*返回json数据的在线接口: https://dog.ceo/api/breeds/image/random */
// js对象 var obj = { name: 'tom', age: 18, likes:['football', 'basketball', 'pingpang'] } // js数组 var arr = [ { name: 'tom', age: 18, likes:['football', 'basketball', 'pingpang'] }, { name: 'jack', age: 21, likes:['pingpang'] } ]
-
JSON对象
- 用途: 专门用来做 json 字符串与 js 对象/数组之间的相互转换的内置对象
- 语法
- JSON.stringify(obj/arr)
- js对象/数组 ==> 转换为json字符串
- JSON.parse(json)
-
json字符串 ==> 转换为js对象/数组
/* JSON对象 */ /* 1. 将js对象/数组转换为json字符串: JSON.stringify() */ const personJson = JSON.stringify(person) console.log(personJson) /* 2. 将json字符串解析为js对象/数组: JSON.parse() */ const person2 = JSON.parse(personJson) console.log(person2)
-
- JSON.stringify(obj/arr)
面试题
- 说说你对JSON的理解
- 比较一下 JSON 与 XML
- 利用 JSON 对象实现对象深拷贝
4. Object扩展
存取器属性 (次重要)
-
get propertyName(){} 用来得到当前属性值的回调函数 ==> getter
-
set propertyName(value){} 用来监视当前属性值变化的回调函数 ==> setter
/* 需求: 一个人有姓 / 名 / 姓名 3个属性, 要求: 1. 姓名组成: 姓-名 2. 改变姓或者名, 姓名也会对应改变 3. 改变姓名, 姓和名也会对应改变 */ const p = { firstName: 'A', lastName: 'B', // fullName: 'A-B' // 不能实现需求2与3 /* getter在读取属性值时自动调用, 返回值作为属性值, this是当前对象 */ get fullName () { console.log('fullName getter') return this.firstName + '-' + this.lastName }, /* setter在设置新的属性值时自动调用, 用来监视属性值的变化, this是当前对象 */ set fullName (value) { console.log('fullName setter', value) const names = value.split('-') this.firstName = names[0] this.lastName = names[1] } } console.log(p.fullName) p.firstName = 'C' p.lastName = 'D' console.log(p.fullName) // 导致对应的getter调用返回属性值 p.fullName = 'E-F' // 导致对应的setter调用 ==> 根据需求去更新firstName与lastName console.log(p.firstName, p.lastName)
Object.defineProperty() (重要)
-
文档: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty
-
功能: 为对象添加新属性,或者修改已有属性
-
语法: Object.defineProperty(obj, prop, descriptor)
- obj为目标对象
- prop为属性名
- descriptor为属性描述符 ==> 描述属性相关信息的配置对象
-
get: 属性的 getter 函数
-
set: 属性的 setter 函数
-
value: 属性的初始值
-
writable: 标识属性值是否可修改的布尔值
-
enumerable: 标识是否可以被枚举遍历的布尔值
-
configurable: 标识是否可以重新定义的布尔值
/* 需求: 给一个人(有姓/名) 添加姓名属性, 要求: 1. 姓名组成: 姓-名 2. 改变姓或者名, 姓名也会对应改变 3. 改变姓名, 姓和名也会对应改变 */ 'use strict' const p = { firstName: 'A', lastName: 'B' } Object.defineProperty(p, 'fullName', { /* getter在读取属性值时自动调用, 返回值作为属性值, this是当前对象 */ get: function () { console.log('fullName getter') return this.firstName + '-' + this.lastName }, /* setter在设置新的属性值时自动调用, 用来监视属性值的变化, this是当前对象 */ set: function (value) { console.log('fullName setter', value) const names = value.split('-') this.firstName = names[0] this.lastName = names[1] }, enumerable: true, // 可以枚举遍历 }) console.log(p.fullName) p.firstName = 'C' p.lastName = 'D' console.log(p.fullName) // 导致对应的getter调用返回属性值 p.fullName = 'E-F' // 导致对应的setter调用 ==> 根据需求去更新firstName与lastName console.log(p.firstName, p.lastName) Object.defineProperty(p, 'foo', { value: 'abc', // 指定初始值 writable: false, // 是否可修改 configurable: false, // 是否可以重新定义 enumerable: false, // 是否可枚举遍历 }) console.log(p.foo) // p.foo = 'cba' // 不能修改只读属性 // console.log(p.foo) // Object.defineProperty(p, 'foo', { // 不能重新定义 // configurable: true // }) // keys()得到指定对象自身可枚举的属性名的数组 ==> 没有foo属性 Object.keys(p).forEach(key => { console.log(key, p[key]) })
-
Object.defineProperties() (了解)
- 功能: 与defineProperty类似, 但可以一次定义多个属性
- 语法: Object.defineProperties(obj, descriptors)
-
obj: 目标对象
-
descriptors:包含一个或多个属性描述符的对象
/* Object.defineProperties() (了解) 功能与defineProperty类似, 但可以一次定义多个属性 */ var obj = { name: 'foo' } Object.defineProperties(obj, { color: { value: "yellow", enumerable: true }, length: { value: "10m", } }) console.log(obj)
-
Object.create() (次重要)
-
功能: 用于创建指定对象的子对象, 并可以扩展新的属性
-
语法: Object.create (prototype, descriptors)
-
prototype: 指定隐式原型对象(也就是父对象)
-
descriptors: 包含一个或多个属性描述符的对象
/* Object.create() (次重要) - 功能: 用于创建指定对象的子对象, 并可以扩展新的属性 - 语法: Object.create (prototype, descriptors) - prototype: 指定隐式原型对象(也就是父对象) - descriptors: 包含一个或多个属性描述符的对象 */ const obj1 = { name1: 'abc' } // 创建一个obj1的子对象, 不扩展新属性 const obj2 = Object.create(obj1) console.log(obj2, obj2.name1) // obj2的原型对象为obj1, 也就是obj2是obj1的子对象 // 创建一个obj1的子对象, 扩展新属性 const obj3 = Object.create(obj1, { name2: { value: 'aaa', enumerable: true }, name3: { value: 'bbb' } }) console.log('obj3', obj3) //创建一个干净的对象: 没有自己的属性也没有原型对象 const obj4 = Object.create(null) console.log('obj4', obj4)
-
面试题
- 给对象定义属性的多种方式
- 说说属性的getter与setter函数
- 如何创建一个对象的子对象
5. 数组的扩展(非常重要)
API
-
Array.prototype.forEach(function(item, index){}) : 遍历数组
-
Array.prototype.indexOf(value) : 得到值在数组中的第一个下标
-
Array.prototype.lastIndexOf(value) : 得到值在数组中的最后一个下标
-
Array.prototype.map(function(item, index){}) : 遍历数组返回一个新的数组
-
Array.prototype.filter(function(item, index){}) : 遍历过滤出一个新的子数组
-
Array.prototype.some(function(item, index){}): 判断是否有一个元素满足条件
-
Array.prototype.every(function(item, index){}): 判断是否所有元素都满足条件
-
Array.prototype.reduce(function(preTotal, item, index){}) : 遍历返回一个累加的结果
练习
// 1. 输出arr中所有的值和对应的下标
// 2. 得到arr中第一个3的下标和最后一个3的下标
// 3. 判断arr中有没有奇数的元素
// 4. 判断arr中是否全部元素都是奇数
// 5. 得到一个由arr中值大于5的元素组成的数组
// 6. 得到一个比arr中每个元素都大10的数组
// 7. 得到arr中所有奇数的和
// 8. 得到arr中所有奇数加10后组成的数组
const arr = [6, 3, 5, 7, 3, 8]
// 1. 输出arr中所有的值及对应的下标
arr.forEach((item, index) => {
console.log(item, index)
})
// 2. 得到arr中第一个3的下标和最后一个3的下标
console.log(arr.indexOf(3), arr.lastIndexOf(3))
// 3. 判断arr中有没有奇数的元素
console.log(arr.some(function (item) {
return item%2===1
}))
// 4. 判断arr中是否全部元素都是奇数
console.log(arr.every(function (item) {
return item%2===1
}))
// 5. 得到一个由arr中值大于5的元素组成的数组
console.log(arr.filter(function (item) {
return item>5
}))
// 6. 得到一个比arr中每个元素都大10的数组
console.log(arr.map(function (item) {
return item + 10
}))
// 7. 得到arr中所有奇数的和
console.log(arr.reduce(function (preTotal, item) {
return preTotal + (item%2===1 ? item : 0)
}, 0))
// 8. 得到arr中所有奇数加10后组成的数组
console.log(arr.reduce(function (pre, item) {
if (item%2===1) {
pre.push(item + 10)
}
return pre
}, []))
面试题
-
说出几个开发中常用的数组方法
push,indexof,filter,reduce,find,some,every
-
对数组[6, 3, 5, 7, 3, 8]进行去重处理
var arr = [6,3,5,7,3,8];
-
对多维数组进行扁平化处理
// 扁平化操作==》多维数组变一维数组 var arr = [1,[2,[4,2,{}]]]
6. 函数的扩展(重要)
API
-
Function.prototype.bind(thisArg, arg1, arg2, …)
-
Function.prototype.call(thisArg, arg1, arg2, …)
-
Function.prototype.apply(thisArg, [argsArray])
面试题
- 区别call与bind
- 自定义call与bind
7. Error
理解
-
文档:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Error
-
JS引擎在解析执行JS代码时发现存在错误时,会自动抛出特定类型包含特定message的error对象
-
当我们判断出程序运行不满足我们的需求时, 可以手动抛出error对象
-
Error有3个常见的子类型
- ReferenceError: 引用了不存在的变量
- TypeError:类型不对
- SyntaxError: 语法错误
-
一旦抛出了错误, 我们如果没有捕获处理,程序就会中断运行
-
错误处理
- 抛出错误: throw new Error(‘错误信息’)
- 捕获错误:try { 可能出错的代码 } catch (error) {}
-
注意:throw抛出的可以是任意类型值, 而不仅仅是error对象
编码测试
/*
Error有3个常见的子类型
- ReferenceError: 引用了不存在的变量
- TypeError:类型不对
- SyntaxError: 语法错误
*/
/* 演示常见的内置错误 */
// console.log(a) // Uncaught ReferenceError: a is not defined
// console.log('-----') // 不会执行 一旦抛出了错误, 我们如果没有捕获处理,程序就会中断运行
// var a = {}
// a() // Uncaught TypeError: a is not a function
// var a = "你的外号叫 "土豆"" // Uncaught SyntaxError: Unexpected identifier
/* 手动抛出错误 */
function fn(day) {
if (day<1 || day>31) {
throw new Error('日号必须在1到31之间')
}
console.log('今天是' + day + '号')
}
// 捕获错误
try {
fn(21)
fn(-1)
} catch (e) {
alert(e.message)
}
console.log('catch之后的处理')
try {
throw 2 // throw本质上可以抛出任意类型值
} catch (e) {
console.log('e', e)
}
面试题
- 说出3种常见的错误
- 说出错误的2种处理
了解完ES5.1,下一章,让我们快速进入ES6+的学习