了解面向对象编程的基础概念及构造函数的作用,体会 JavaScript 一切皆对象的语言特征,掌握常见的对象属性和方法的使用。

  • 了解面向对象编程中的一般概念
  • 能够基于构造函数创建对象
  • 理解 JavaScript 中一切皆对象的语言特征
  • 理解引用对象类型值存储的的特征
  • 掌握包装类型对象常见方法的使用

    一、面向对象

    了解面向对象的基础概念,能够利用构造函数创建对象。

1.0 字面量对象

什么是字面量?看表面就知道你是什么类型。
(string、number、boolean、symbol、null、undefined)
(object [纯粹的对象、数组、函数])

  1. let str = 'asdfadsf'
  2. let arr = ['a', 'b']
  3. let obj = { uname: 'zxx', age: 20 } // 字面量对象
  4. let obj1 = {
  5. uname: 'zs',
  6. age: 30,
  7. height: 180,
  8. 'my-nickname': '老汤', // 这种属性名带 - ,所以必须加引号
  9. say: function () {
  10. console.log('会说话')
  11. },
  12. wash: function () {
  13. console.log('会洗衣服')
  14. }
  15. }
  16. // ------------------------- 访问属性值 -------------------------
  17. // 语法:1 对象.属性 2 对象[属性]
  18. // console.log( obj1.uname )
  19. // console.log( obj1['uname'] ) // 加上引号,表示找具体的叫做 uname 的属性
  20. // ###### 个别情况,访问对象的属性,必须用方括号 #####
  21. console.log(obj1['my-nickname']) // 必须使用[]的情况之一,属性名有中横线
  22. // 使用变量表示属性名
  23. let a = 'age'
  24. console.log(obj1[a]) // 属性名使用变量,则必须使用[]语法,而且因为a是变量,不能加引号

小结:

  1. 定义对象的时候,如果属性名有特殊符号,比如中横线,则属性名必须加引号
  2. 访问对象的属性,可以使用点语法或者方括号语法
  3. 如果属性名有特殊符号,则访问属性的时候,必须用方括号 obj1['my-nickname']
  4. 如果属性使用变量表示,则访问属性的时候,必须用方括号 let a = 'age'; obj1[a]

    1.1 构造函数

    构造函数是专门用于创建对象的函数,如果一个函数使用 new 关键字调用,那么这个函数就是构造函数。
    1. <script>
    2. // 定义函数
    3. function foo() {
    4. console.log('通过 new 也能调用函数...');
    5. }
    6. // 调用函数
    7. new foo;
    8. </script>
    ```javascript // 声明一个函数(我有两个身份,一个就是当做普通函数调用;另一个是当做构造函数来用) function Person(n) { console.log(n) // 在实例化对象的时候,会自动执行构造函数 // 构造函数中,一般不写return // return new Date() // 返回一个对象,在 new Person() 之后,就会得到这里返回的对象 }

// 如果使用 new 来 new Person() ,这个时候,Person就充当了构造函数的角色 // 使用构造函数,创建的对象;也叫做实例化对象 let obj = new Person(100) // console.log(obj) // Person {} 得到对象 // console.log(typeof obj) // object

let obj1 = new Person(200) let obj2 = new Person(300)

总结:

1. 在实例化对象的时候,构造函数会自动执行
2. 使用 `new` 关键字调用函数的行为被称为实例化
3. 实例化构造函数时没有参数时可以省略 `()`,不过还是建议加上小括号
4. 构造函数的返回值即为新创建的对象
5. 构造函数内部的 `return` 返回的值无效!除非返回的是一个对象

注:实践中为了从视觉上区分构造函数和普通函数,习惯将构造函数的首字母大写。
<a name="xDIhG"></a>
## 1.2 实例成员
通过构造函数创建的对象称为**实例对象**,实例对象中的属性和方法称为**实例成员**。
```html
<script>
  // 构造函数
  function Person() {
    // 构造函数内部的 this 就是实例对象

    // 实例对象中动态添加属性
    this.name = '小明';
    // 实例对象动态添加方法
    this.sayHi = function () {
      console.log('大家好~');
    }
  }

  // 实例化,p1 是实例对象
  // p1 实际就是 构造函数内部的 this
  let p1 = new Person();

  console.log(p1);
  console.log(p1.name); // 访问实例属性
  p1.sayHi(); // 调用实例方法
</script>

课堂代码:

function Person(u, a) {
  // 每个对象通用的属性、方法,可以放到构造函数里面;
  // 使用 ”this.属性 = 值” 这样的语法,为对象添加通用的属性
  // 构造函数中的 this 表示创建的实例对象,即 obj1 或 obj2
  this.uname = u
  this.age = a
  this.say = function () {
    console.log('哈哈哈')
  }
}

// 通过new 构造函数得到的对象,叫做实例对象
let obj1 = new Person('老段', 80)
console.log(obj1)

let obj2 = new Person('大飞哥', 50)
console.log(obj2)

总结:

  1. 构造函数内部 this 实际上就是实例对象,为其动态添加的属性和方法即为实例成员
  2. 为构造函数传入参数,动态创建结构相同但值不同的对象
  3. 实例对象的 constructor 属性指向了构造函数(后面讲)
  4. instanceof 用于检测实例对象对应的构造函数(后面讲)

注:构造函数创建的实例对象彼此独立互不影响。

1.3 静态成员

在 JavaScript 中底层函数本质上也是对象类型,因此允许直接为函数动态添加属性或方法,构造函数的属性和方法被称为静态成员。

<script>
  // 构造函数
  function Person(name, age) {
    // 省略实例成员
  }

  // 静态属性
  Person.eyes = 2;
  Person.arms = 2;
  // 静态方法
  Person.walk = function () {
    console.log('^_^人都会走路...');
    // this 指向 Person
    console.log(this.eyes);
  }
</script>

课堂代码:

// 构造函数
function Person() {
  this.uname = 'ddd'
  // this表示实例对象,this.uname 表示给实例对象加属性
}

// 因为函数也是对象,所以可以使用 ”对象.属性” 这个语法
Person.uname = 'lisi'
Person.age = 20
Person.say = function () {
  // 静态方法中的this,表示当前这个构造函数
  console.log(this.age)
}

let obj = new Person()
console.log(obj.uname)  // 调用的是 函数内部通过 this 加的属性

// 调用静态成员
console.log(Person.uname) // 调用的是给函数直接加的静态成员
Person.say() // 调用静态方法

// -----------------------------------------------------
// 内置的 Date、Math,其实都是JS设计者,设计好的内置构造函数
// let d = new Date()
// console.log(d.getFullYear())

// console.log(Math.random())

总结:

  1. 静态成员指的是添加到构造函数本身的属性和方法
  2. 一般公共特征的属性或方法静态成员设置为静态成员
  3. 静态成员方法中的 this 指向构造函数本身
  4. 静态成员,不要使用 name属性,name 属性特指函数的名字。

    二、一切皆对象

    体会 JavaScript 一切皆对象的语言特征,掌握各引用类型和包装类型对象属性和方法的使用。

在 JavaScript 中最主要的数据类型有 6 种,分别是字符串、数值、布尔、undefined、null 和 对象,常见的对象类型数据包括数组和普通对象。其中字符串、数值、布尔、undefined、null 也被称为简单类型或基础类型,对象也被称为引用类型。
在 JavaScript 内置了一些构造函数,绝大部的数据处理都是基于这些构造函数实现的,JavaScript 基础阶段学习的 Date 就是内置的构造函数。

<script>
  // 实例化
    let date = new Date();

  // date 即为实例对象
  console.log(date);


    简单数据类型:字符串、数字、布尔、undefined、null
    (引用类型)复杂数据类型:对象(数组)

</script>

甚至字符串、数值、布尔、数组、普通对象也都有专门的构造函数,用于创建对应类型的数据。

2.1 引用类型

Object

Object 是内置的构造函数,用于创建普通对象。

<script>
  // 通过构造函数创建普通对象
  let user = new Object({name: '小明', age: 15});

  // 这种方式声明的变量称为【字面量】
  let student = {name: '杜子腾', age: 21}

  // 对象语法简写
  let name = '小红';
  let people = {
    // 相当于 name: name
    name,
    // 相当于 walk: function () {}
    walk () {
      console.log('人都要走路...');
    }
  }

  console.log(student.constructor); // 明天讲
  console.log(user.constructor); // 明天讲
  console.log(student instanceof Object); // 明天讲
</script>

课堂代码:

// Object是内置的构造函数

// 1. 直接 new Object(),得到空对象
// let obj1 = new Object()
// // 给对象添加属性、方法;语法,还是 ”对象.属性 = 值”
// obj1.uname = 'zhangsan'
// obj1.age = 20
// obj1.say = function () {
//   console.log(this.age)
// }
// console.log(obj1)
// obj1.say()

// 2. 直接 new Object({key: value, key: value})
let obj2 = new Object({ uname: 'zs', age: 30 })
console.log(obj2)

下图展示了普通对象在内存中的存储方式:普通对象数据保存在堆内存之中,栈内存中保存了普通对象在堆内存的地址。
第2天 - 图1
普能对象在赋值时(**let obj2 = obj**)只是复制了栈内中的地址,而非堆内存中的数据,如下图所示:
第2天 - 图2
普通对象赋值后,无论修改哪个变量另一个对象的数据值也会相当发生改变。
如果给 obj2 赋一个新的值(obj2 = { uname: 'zhangsan', age: 2000}),则 obj 和 obj2 就是完全不同的两个对象了。
第2天 - 图3
课堂代码:

// -------------------------- 原始类型 ----------------------
// let a = 'hello'
// let b = a  // 将 a 的值 hello 赋值给了b

// b = 'hahaha' // 将b的值改为 hahaha

// console.log(a)
// console.log(b)

// ------------------------- 引用类型 -------------------------
let obj = { uname: 'lisi', age: 20 }

let obj2 = obj  // 把obj的值,赋值给obj2

obj2.age = 100  // 修改obj2的age,修改了属性,会影响另一个对象
obj.uname = '老段' // 修改obj的uname,修改了属性,会影响另一个对象

// 给obj2重新赋了一个新值。从此,obj和obj2就是两个不同的对象了
obj2 = { uname: 'zhangsan', age: 2000 } 

console.log(obj)
console.log(obj2)

总结:

  1. 推荐使用字面量方式声明对象,而不是 Object 构造函数
  2. Object.assign 静态方法创建新的对象
  3. Object.keys 静态方法获取对象中所有属性
  4. Object.values 表态方法获取对象中所有属性值

面试回答堆与栈的区别:

  1. 堆和栈是内存中的数据存储空间
  2. 简单类型的数据保存在内存的栈空间中
  3. 引用类型的数据保存在内存的堆空间中,栈内存中存取的是引用类型的地址(房间号)

    Array

    Array 是内置的构造函数,用于创建数组。

    <script>
    // 构造函数创建数组
    let arr = new Array(5, 7, 8);
    
    // 字面量方式创建数组
    let list = ['html', 'css', 'javascript'];
    
    console.log(list.constructor);
    console.log(list instanceof Array);
    </script>
    

    课堂代码: ```javascript // Array 是内置的一个构造函数,通过 new Array 可以得到数组类型的对象 // let arr = [‘a’, ‘b’] // console.log(typeof arr) // object

// 数组也是对象的一种 // 对象(纯粹的对象、数组、函数)

// ————————— 使用Array ——————————————- // let arr = new Array() // 得到一个空数组。和 let arr = [] 一样 // console.log(arr)

// let arr = new Array(‘张三’, ‘李四’) // [‘张三’, ‘李四’] // 和 let arr = [‘张三’, ‘李四’] 是一样的 // console.log(arr)

// let arr = new Array(3) // 只传递一个数字,表示数组有三个成员 // console.log(arr)

数组在内存中的存储方式与普通对象一样,如下图所示:<br />![](https://cdn.nlark.com/yuque/0/2022/jpeg/22014993/1650188579150-f5a479d3-071f-431d-b2c6-1dc464485c99.jpeg)<br />数组在赋值时(`let arr2 = arr`)只是复制了栈内中的地址,而非堆内存中的数据,如下图所示:<br />![](https://cdn.nlark.com/yuque/0/2022/jpeg/22014993/1650264496001-031d5fd4-f730-45c8-9cec-7f299b72b2c0.jpeg)<br />数组赋值后,无论修改哪个变量另一个对象的数据值也会相当发生改变。<br />课堂代码:
```javascript
let arr = ['张三', '李四']
let arr2 = arr  // 把 arr 的地址,赋值给 arr2,这样的话,两个变量指向同一个地址

arr2.push('王五')

console.log(arr)  // ['张三', '李四', '王五']
console.log(arr2) // ['张三', '李四', '王五']

总结:

  1. 推荐使用字面量方式声明数组,而不是 Array 构造函数
  2. 实例方法 push,用于向数组的末尾添加一个或多个元素
  3. 实例方法 pop,用于从数组的末尾删除最后一个元素
  4. 实例方法 unshift,将一个或多个元素添加到数组的开头
  5. 实例方法 splice 删除元素,还可以在删除的位置新增其他元素(相当于是修改)
  6. 实例方法 join 将数组元素拼接成字符串
  7. 实例方法 concat 合并两个数组,生成新数组
  8. 实例方法 indexOf 用于在数组中查找元素,找到则返回它的索引;找不到返回 -1
  9. 实例方法 reverse 反转数组

课堂代码:

let arr = ['亚索', '拉克丝']

// 1. 向数组的末尾,添加一个或多个元素
arr.push('儿童劫', '盲僧')
// console.log(arr) // ['亚索', '拉克丝', '儿童劫', '盲僧']

// 把数组中的  拉克丝和儿童劫  都删除了,同时再新增一个 维克托
// arr.splice(从哪开始删除, 删除几个元素, 添加的新元素, 添加的新元素, .....)
arr.splice(1, 2, '维克托')
// console.log(arr) // ['亚索', '维克托', '盲僧']
// arr.join() --- 默认使用 , 连接数组的每个元素,返回拼接后的字符串
// arr.join('###') --- 表示使用指定的 ### 连接每个数组元素,返回字符串
console.log(arr.join()) // 亚索,维克托,盲僧
console.log(arr.join('###')) // 亚索###维克托###盲僧
console.log(arr.join(''))  // 亚索维克托盲僧

console.log(arr.indexOf('亚索')) // 0
console.log(arr.indexOf('盲僧')) // 2
console.log(arr.indexOf('石头人')) // -1

console.log(arr.reverse()) // ['盲僧', '维克托', '亚索']
  1. 实例方法 sort 对原数组单元值排序(先放一下) ```javascript // ——————————— 对数组进行排序 ——————————— // ——————— sort 的基本认知 ——————— // let arr = [4, 8] // let result = arr.sort(function (a, b) { // // console.log(a, b) // 8 4 // // 根据return的值进行排序 // // return 0 // 不排序,保持原来的顺序 // // return 1 // 返回正数(不换位) // return -1 // 返回负数(换位) // }) // console.log(result)

// let arr = [4, 9, 2, 8, 0, 5, 7] // let result = arr.sort(function (a, b) { // // return a - b // 从小到大排序(升序) // // return b - a // 从大到小排序(降序) // return Math.random() - 0.5 // 随机返回正或负数,则打乱数组 // }) // console.log(result)

let arr = [‘orange’, ‘banana’, ‘apple’, ‘xigua’, ‘appla’] // 认知:字符串也能比较大小(按照Unicode编码比较) let result = arr.sort(function (a, b) { // 升序(从小到大排序) if (a < b) return -1 // if 区间如果只有一行代码,可以去掉 {} if (a > b) return 1 if (a === b) return 0 }) console.log(result)

// let arr = [2, 18, 100, 9] // let result = arr.sort() // 这里可以不传递那个函数 // // 不传递函数,相当于是把数组的每个成员都变为字符串。然后按照Unicode编码升序排序 // console.log(result)

Array的静态方法:

1. Array.from()  ---- 将伪数组转成真数组
1. Array.isArray() ---- 判断元素是否是数组
```javascript
// ---------------------- from 将伪数组转成真数组 ----------------
// 伪数组(实际是对象)
let obj = {
  0: 'aa',
  1: 'bb',
  length: 2
}

let arr = Array.from(obj)
console.log(arr) // ['aa', 'bb']
// 转成真数组后,才能 调用数组方法
arr.push('ccc')
console.log(arr)

// ---------------------- 判断变量是否是数组类型 --------------------
console.log(Array.isArray([])) // true
console.log(Array.isArray(['a', 'c'])) // true
console.log(Array.isArray(obj)) // false
console.log(Array.isArray(123)) // false

语法相似的实例方法:

  1. 实例方法 forEach 用于遍历数组,替代 for 循环 ```javascript // ———————- forEach 遍历数组 ——————————— // [‘a’, ‘b’, ‘c’].forEach(function (item, index, self) { // // item表示数组的每一项,分别表示 a 、b 、c // // console.log(item)

// // index表示数组的下标,分别表示 0 、1 、2 // // console.log(index)

// // self表示当前这个数组 // // console.log(self) // }); // 关于 item、index、self,如果不使用self可以省略、如果不使用index也可以省略

[‘a’, ‘b’, ‘c’].forEach(function (item) { console.log(item) }); // 这里加分号

// ———————— 配合箭头函数 —————————————— // [‘a’, ‘b’, ‘c’].forEach(() => {}) // [‘a’, ‘b’, ‘c’].forEach((item, index, self) => { }) // [‘a’, ‘b’, ‘c’].forEach((item) => {}) // [‘a’, ‘b’, ‘c’].forEach(item => { console.log(item) }) [‘a’, ‘b’, ‘c’].forEach(item => console.log(item))


2. 实例方法 `filter` 根据条件,过滤数组元素,符合条件的元素组成新数组
2. 实例方法 `map` 循环遍历原数组,函数的返回值组成新数组
```javascript
// ----------------- filter -----------------------------
// let arr = [4, 2, 9, 5, 0, 8]
// let result = arr.filter(function (item, index, self) { })
// let result = arr.filter(function (item) {
//   // 这里要返回一个条件
//   return item > 5
// })
// let result = arr.filter((item) => {return item > 5})
// let result = arr.filter(item => item > 5)
// console.log(result)

// 使用filter删除数组元素(删除id=7的元素)
let data = [
  { id: 1, name: 'zs', age: 20 },
  { id: 3, name: 'lisi', age: 30 },
  { id: 7, name: 'wangwu', age: 23 },
  { id: 15, name: 'abc', age: 26 }
]

let result = data.filter(item => {
  // console.log(item)
  // reutrn 条件 // 符合条件的将组成新的数组
  return item.id !== 7
})
console.log(result)

// -------------------- map ---------------------------
// let arr = [4, 2, 9, 5, 0, 8]
// 需要,得到新数组,数组中放原数组每个元素的平方值
// let result = arr.map(function (item) {
//   return item * item  // 返回每个元素的平方 
// })
// let result = arr.map(item => item * item)
// console.log(result)
  1. 实例方法 find,根据条件查找符合条件的第1个元素,找到返回这个元素;找不到返回null
  2. 实例方法 findIndex,根据条件查找符合条件的第1个元素的下标,找到则返回这个下标,找不到返回 -1 ```javascript // ———————————- find ————————————- // let arr = [3, 8, 5, 9, 1, 0, 2] // // let result = arr.find(function (item, index, self) { }) // // let result = arr.find(item => { // // // return 条件 // // return item > 5 // // }) // let result = arr.find(item => item > 5) // console.log(result)
// ----------------------- findIndex -------------------------
let arr = [3, 8, 5, 9, 1, 0, 2]
let result = arr.findIndex(item => item > 5)
console.log(result)

6. 实例方法 `some`,判断数组中是否有一些元素符合条件,如果有则返回true;没有返回false
6. 实例方法 `every`,判断数组中是否每个元素都符合条件,如果都符合条件返回true,否则返回false
```javascript
// ----------------------- some -------------------------
// let arr = [3, 8, 5, 9, 1, 0, 2]
// let result = arr.some(item => item > 5)
// console.log(result) // true

// ----------------------- every -------------------------
let arr = [3, 8, 5, 9, 1, 0, 2]
let result = arr.every(item => item > 5)
console.log(result) // false
  1. 实例方法 reduce,数组求和 ```javascript // let arr = [4, 2, 8, 9, 5]

// ————————- 没有初始值 ——————————- // let result = arr.reduce(function (总和, 当前的元素) {

// })

// let result = arr.reduce(function (total, curr) { // // 第1循环:total = 数组的第1个元素 curr = 数组的第2个元素 // // 第2循环:total = 总和 curr = 数组的第3个元素 // // 第3循环:total = 总和 curr = 数组的第4个元素 // // 第4循环:total = 总和 curr = 数组的第5个元素 // return total + curr // }) // console.log(result)

// ————————- 有初始值 ——————————- let arr = [4, 2, 8, 9, 5] // let result = arr.reduce(function (总和, 数组元素) { }, 初始值)

let result = arr.reduce(function (total, curr) { // 第1次循环:total = 初始值 curr = 数组第1个元素 // 第1次循环:total = 总和 curr = 数组第2个元素 // …… return total + curr }, 100)

console.log(result)

<a name="Ad3Yl"></a>
### RegExp
`RegExp` 内置的构造函数,用于创建正则表达式。<br />Regular Expression
```html
<script>
  // 构造函数创建正则
  let reg = new RegExp('\\d', 'i');
  let reg = new RegExp(/\d/, 'i')

  // 字面量方式创建正则
  // let reg = /(\d)/i;

  reg.exec('123');
</script>
// 匹配连续的4个数字
// let reg = /\d\d\d\d/g
// let reg = /\d{4}/g
// let reg = /[0-9]{4}/g

// 匹配连续的4个数字,要求每组数字 第1个数字和第2个数字相同;第3个数字和第4个数字相同
// let str = '0011 2233 4545 6776 8998'

// let reg = /(\d)\1(\d)\2/g
// (\d) 使用小括号,表示 捕获 \d 匹配的那个值
// \1   表示匹配的值,必须和第1个小括号匹配的值相同
// \2   表示匹配的值,必须和第2个小括号匹配的值相同
// console.log(str.match(reg))

// 匹配连续的4个数字,要求14位相同、23位相同
// let reg = /(\d)(\d)\2\1/g
// console.log(str.match(reg))

// 匹配连续的4个数字,要求13位相同、24位相同
// let reg = /(\d)(\d)\1\2/g
// console.log(str.match(reg))

let str = 'ES6 and H5'
// ES666 and H555
let result = str.replace(/(\d)/g, '$1$1$1')
console.log(result)

总结:

  1. 推荐使用字面量定义正则表达式,而不是 RegExp 构造函数
  2. RegExp 静态属性 $1、$2、$3、… 获取正则分组单元

补充:当使用构造函数创建正则时有两种写法:

<script>
  // 使用 // 定义正则
  let reg = new RegExp(/\d/);

  // 或者使用 '' 定义正则
  // 如果使用引号定义正则时,\d、\s、\w
    需要多添加一个 \
  let reg1 = new RegExp('\\d');
</script>

2.2 包装类型

在 JavaScript 中的字符串、数值、布尔具有对象的使用特征,如具有属性和方法,如下代码举例:

<script>
  // 字符串类型
  let str = 'hello world!';
     // 统计字符的长度(字符数量)
  console.log(str.length);

  // 数值类型
  let price = 12.345;
  // 保留两位小数
  price.toFixed(2);
</script>

之所以具有对象特征的原因是字符串、数值、布尔类型数据是 JavaScript 底层使用 Object 构造函数“包装”来的,被称为包装类型。
课堂代码:

// 数组、对象,不用包装,人家本来就是对象
// let arr = []
// let obj = {}
// console.log(typeof arr)
// console.log(typeof obj)

// 在把一些原始类型,比如字符串、数字当做对象使用的时候
// JS会自动包装他们,让他们变为对象,然后再调用这些方法
let str = 'adfasdfdsfdf'   // let obj = new String('adfasdfdsfdf')
// console.log(typeof str) // string
// let obj = new String('adfasdfdsfdf') // 实际中,这行不需要的;老师为了演示JS是怎么包装的

let result = str.match(/a/g)
console.log(result)

let num = 3.1415926
// let obj2 = new Number(3.1415926)
console.log(num.toFixed(2))


// 是不是只要使用字符串,就会把它包装成对象呢?
// 是不是只要使用数字,就会把它包装成对象呢?
// 不是的,平时用还是字符串,还是数字;只有在把字符串、数字当做对象使用的时候,才会包装成对象
console.log('hello' + ' world')
console.log(6 * 8)

String

String 是内置的构造函数,用于创建字符串。

<script>
  // 使用构造函数创建字符串
  let str = new String('hello world!');

  // 字面量创建字符串
  let str2 = '你好,世界!';

  // 检测是否属于同一个构造函数
  console.log(str.constructor === str2.constructor); // true
  console.log(str instanceof String); // false
</script>

总结:

  1. 推荐使用字面量方式声明字符串,而不是 String 构造函数
  2. 实例属性 length 用来获取字符串的度长
  3. 实例方法 split 用来将字符串拆分成数组
  4. 实例方法 toUpperCase 用于将字母转换成大写
  5. 实例方法 toLowerCase 用于将字母转换成小写

    let str = 'hello world'
    // 如果把字符串当做对象用,JS会自动包装字符串为对象  let obj = new String('hello world')
    // console.log(str.length) // 11
    // console.log(str.split('o')) // ['hell', ' w', 'rld']
    // console.log(str.split('')) // ['h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
    // console.log(str.split(' ')) // ['hello', 'world']
    // console.log(str.toUpperCase()) // HELLO WORLD
    console.log('HELLO World'.toLowerCase()) // hello world
    
  6. 实例方法 slice 用于字符串截取

  7. 实例方法 substring 用于字符串截取

    // 字符串截取
     // console.log('abcdefg'.substring(2, 4)) // cd 包括位置2的字符,不包括位置4的字符
     // console.log('abcdefg'.substring(2)) // cdefg 从位置2的字符开始,一直截取到结尾
    
     // console.log('abcdefg'.slice()) // abcdefg
     // console.log('abcdefg'.slice(2)) // cdefg
     // console.log('abcdefg'.slice(2, 4)) // cd
     console.log('abcdefg'.slice(2, -2)) // cde   2表示从位置2开始截取,-2表示从后向前数两个字符
    
  8. 实例方法 substr用于字符串截取(不建议使用了)

  9. 实例方法 indexOf 检测是否包含某字符,包含则返回字符的位置,不包含则返回 -1
  10. 实例方法 startsWith 检测是否以某字符开头
  11. 实例方法 endsWith 检测是否以某字符结尾

    // console.log('abcdefg'.indexOf('c')) // 2
     // console.log('abcdefg'.indexOf('x')) // -1
    
     // console.log('abcdefg'.startsWith('abc')) // true
     // console.log('abcdefg'.startsWith('cde')) // false
     // console.log('abcdefg'.startsWith('cd', 2)) // true.表示从位置2开始算起,开头是cd吗?是
    
     console.log('abcdefg'.endsWith('fg')) // true
     console.log('abcdefg'.endsWith('e')) // false
     console.log('abcdefg'.endsWith('e', 5)) // true. 5表示先截取5个字符,然后看这5个字符的结尾是否是e,答案是
    
  12. 实例方法 replace 用于替换字符串,支持正则匹配

  13. 实例方法 padStart 固定长度字符开始位置打补丁
  14. 实例方法 padEnd 固定长度字符结束位置打补丁
  15. 实例方法 match 用于查找字符串,支持正则匹配
  16. 实例方法 trim 用于去除字符串两边的空白 ```javascript // console.log(‘abcdefg’.replace(‘a’, ‘A’)) // Abcdefg // console.log(‘abcadeafg’.replace(‘a’, ‘A’)) // Abcadeafg 默认只替换找到的第1个a // console.log(‘abcadeafg’.replace(/a/g, ‘A’)) // AbcAdeAfg

// console.log(‘abc’.padStart(5, ‘@’)) // @@abc 使用@把字符串补充到5位长度 // console.log(‘abc’.padEnd(5, ‘.’)) // abc.. 使用.把字符串补充到5位长度

// console.log(‘ abcd ‘.trim()) // 去掉字符串前后的空格 document.querySelector(‘button’).addEventListener(‘click’, function () { // 获取输入框的值 let val = document.querySelector(‘input’).value val = val.trim() // 去掉字符串两边的空白 console.log(val) })

注:String 也可以当做普通函数使用,这时它的作用是强制转换成字符串数据类型。
<a name="GvfGv"></a>
### Number
`Number` 是内置的构造函数,用于创建数值。
```html
<script>
  // 使用构造函数创建数值
  let x = new Number('10');
  let y = new Number(5);

  // 字面量创建数值
  let z = 20;

  // 检测是否属于同一个构造函数
  console.log(x.constructor === z.constructor);
</script>

课堂代码:

// let num = 3.1415926
// console.log(num.toFixed(3)) // 保留3位小数(会自动四舍五入)3.142

// 使用数字在调用方法的时候,必须先声明变量,不要直接 3.1415.toFixed(2)
// console.log(3.14159.toFixed(3))

// -------------------- 关于数字类型的方法 --------------------

// parseInt() 和 parseFloat() 是JS中,独立的函数,可以直接调用
// console.log(parseInt(3.74)) // 3
// console.log(parseInt('123abc456')) // 123
// console.log(parseInt('abc123')) // NaN

// console.log(parseFloat('3.14')) // 3.14
// console.log(parseFloat('3.14.15.16.17')) // 3.14
// console.log(parseFloat('3.14,15.16,17')) // 3.14

// Number()  --  强制转换成数字。看整个字符串,能转则转,转不了则NaN
console.log(Number(3.14)) // 3.14
console.log(Number('123abc')) // NaN

总结:

  1. 推荐使用字面量方式声明数值,而不是 Number 构造函数
  2. 实例方法 toFixed 用于设置保留小数位的长度

注:Number 也可以当做普通函数使用,这时它的作用是强制转换成数值数据类型。

Boolean

Boolean 是内置的构造函数,用于创建布尔值。

<script>
  // 使用构造函数创建布尔类型
  let locked = new Boolean('10');

  // 字面量创建布尔类型
  let flag = true;

  // 检测是否属于同一个构造函数
  console.log(locked.constructor === flag.constructor);
</script>

总结:

  1. 推荐使用字面量方式声明布尔值,而不是 Boolean 构造函数

注:Boolean 也可以当做普通函数使用,这时它的作用是强制转换成布尔类型数据,由其它数据类型转换成布尔类型的数据被称为真值(truly)或假值(falsly)。

哪些内容在转成布尔时是false?
0
0.0
''
null
NaN           not a number  非数字
undefined
false

除此之外,其他所有值在转成布尔的时候 ,都是true
[]   ===>  true
{}   ===>  true
' '  ===>  true

2.3 写在最后

至此对 JavaScript 有了更深的理解,即 JavaScript 中一切皆为对象,还有以前学习的 window、Math 对象,最后补充一点无论是引用类型或是包装包类型都包含两个公共的方法 toStringvalueOf
当把调用者,当做字符串使用的时候,会自动调用 toString() ;如果没有toString则调用valueOf
当把调用者,当做数字使用的时候,会自动调用valueOf();如果没有valueOf则调用toString。
这两个方法可以自己定义(如果自己定义了这两个方法,则优先使用我们自己定义的)

<script>
function abc() {

}
// 手动修改函数的 toString()
abc.toString = function () {
  return 12345
}

// 把函数当做字符串使用,会自动调用函数的toString()
console.log(String(abc)) // 把函数转成字符串使用
console.log(abc + '') // 把函数转成字符串使用(一个变量和字符串拼接的时候,都会把这个变量先转成字符串)
alert(abc) // alert方法会自动把变量的值转成字符串 


// ----------------- 面试题 -----------------
// 自己创建一个函数,对传入的参数进行求和;函数的调用形式如下:
// fn(1, 2, 3) // 6
// fn(1)(2, 3) // 6
// fn(1, 2)(3) // 6
// fn(1)(2)(3) // 6
// fn(1, 2)(3)(4)(5, 6)(7) // 28

// 柯里化
</script>

总结:

  1. valueOf 方法获取原始值,数据内部运算的基础,很少主动调用该方法
  2. toString 方法以字符串形式表示对象

    三、总结

  3. 构造函数的问题,放一边去,没用

    1. let 对象 = new 构造函数()
    2. 在构造函数中,可以通过 this.属性 = 值 为实例对象添加属性或方法
    3. 因为函数也是对象;所以也可以给函数加属性或方法,语法 函数.属性 = xxx
  4. 创建对象、数组、正则表达式,也可以通过new创建
    1. 创建对象
      1. let obj = { id: 1, name: ‘zs’ }
      2. let obj = new Object({ id: 1, name: ‘zs’ })
    2. 创建数组
      1. let arr = [‘aa’, ‘bb’]
      2. let arr = new Array(‘aa’, ‘bb’)
    3. 创建正则表达式
      1. let reg = /\d+/g
      2. let reg = new RegExp(/\d+/, ‘g’)
  5. 数组方法
    1. push()
    2. pop
    3. unshift()
    4. splice()
    5. forEach()
    6. filter()
    7. map()
    8. some()
    9. every()
    10. find()
    11. findIndex()
    12. reduce()
    13. ………..