对象的方法补充

  • hasOwnProperty
    • 对象是否有某一个属于自己的属性(不是在原型上的属性)
  • in/for in 操作符
    • 判断某个属性是否在某个对象或者对象的原型上
  • instanceof
    • 用于检测构造函数(Person、Student类)的pototype,是否出现在某个实例对象的原型链上
  • isPrototypeOf
    • 用于检测某个对象,是否出现在某个实例对象的原型链上

class定义类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Person {

}

// 创建实例对象
var p1 = new Person()
var p2 = new Person()
console.log(p1, p2)

// 另外一种定义方法: 表达式写法(了解, 少用)
var Student = class {

}
var foo = function() {

}

var stu1 = new Student()
console.log(stu1)

类和构造函数的异同

  • 我们来研究一下类的一些特性:
    • 你会发现它和我们的构造函数的特性其实是一致的;
    • image.png

类的构造函数

  • 如果我们希望在创建对象的时候给类传递一些参数,这个时候应该如何做呢?
    • 每个类都可以有一个自己的构造函数(方法),这个方法的名称是固定的constructor;
    • 当我们通过new操作符,操作一个类的时候会调用这个类的构造函数constructor;
    • 每个类只能有一个构造函数,如果包含多个构造函数,那么会抛出异常;
  • 当我们通过new关键字操作类的时候,会调用这个constructor函数,并且执行如下操作:
    • 1.在内存中创建一个新的对象(空对象);
    • 2.这个对象内部的[[prototype]]属性会被赋值为该类的prototype属性;
    • 3.构造函数内部的this,会指向创建出来的新对象;
    • 4.执行构造函数的内部代码(函数体代码);
    • 5.如果构造函数没有返回非空对象,则返回创建出来的新对象;

类的实例方法

  • 在上面我们定义的属性都是直接放到了this上,也就意味着它是放到了创建出来的新对象中:
    • 在前面我们说过对于实例的方法,我们是希望放到原型上的,这样可以被多个实例来共享;
    • 这个时候我们可以直接在类中定义;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Person {
// 1.类中的构造函数
// 当我们通过new关键字调用一个Person类时, 默认调用class中的constructor方法
constructor(name, age) {
this.name = name
this.age = age
}

// 2.实例方法
// 本质上是放在Person.prototype
running () {
console.log(this.name + " running~")
}
eating () {
console.log(this.name + " eating~")
}
}

// 创建实例对象
var p1 = new Person("why", 18)

// 使用实例对象中属性和方法
console.log(p1.name, p1.age)// why 18
p1.running() //why running~
p1.eating() //why eating~

// 研究内容
console.log(Person.prototype === p1.__proto__)//true
console.log(Person.running) //undefined
console.log(Person.prototype.running)
// ƒ running() {
// console.log(this.name + " running~")
// }

类的访问器方法

我们之前讲对象的属性描述符时有讲过对象可以添加setter和getter函数的,那么类也是可以的
image.png

类的静态方法

静态方法通常用于定义直接使用类来执行的方法,不需要有类的实例,使用static关键字来定义:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var names = ["abc", "cba", "nba", "mba"]
class Person {
constructor(name, age) {
this.name = name
this.age = age
}

// 实例方法
running () {
console.log(this.name + " running~")
}
eating () { }

// 类方法(静态方法)
static randomPerson () {
console.log(this)
var randomName = names[Math.floor(Math.random() * names.length)]
return new this(randomName, Math.floor(Math.random() * 100))
}
}

var p1 = new Person()
p1.running()
p1.eating()
var randomPerson = Person.randomPerson()
console.log(randomPerson)

image.png

ES6类的继承 - extends

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 定义父类
class Person {
constructor(name, age) {
this.name = name
this.age = age
}

running () {
console.log(this.name, " ex-running~")
}
eating () {
console.log(this.name, " ex-eating~")
}

}

class Student extends Person {
constructor(name, age, sno, score) {
super(name, age)
this.sno = sno
this.score = score
}
studying () {
console.log(this.name, " my-studying~")
}
}

var stu1 = new Student("why", 18, 111, 100)
stu1.running()
stu1.eating()
stu1.studying()

super关键字

  • 我们会发现在上面的代码中我使用了一个super关键字,这个super关键字有不同的使用方式:
  • 注意:在子(派生)类的构造函数中使用this或者返回默认对象之前,必须先通过super调用父类的构造函数!
  • super的使用位置有三个:子类的构造函数、实例方法、静态方法;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
	class Animal {
running () {
console.log("ex-running")
}
eating () {
console.log("ex-eating")
}

static sleep () {
console.log("static animal sleep")
}
}

class Dog extends Animal {
// 子类如果对于父类的方法实现不满足(继承过来的方法)
// 重新实现称之为重写(父类方法的重写)
running () {
console.log("dog四条腿")
// 调用父类的方法
super.running()
// console.log("running~")
// console.log("dog四条腿running~")
}

static sleep () {
console.log("趴着")
super.sleep()
}
}

var dog = new Dog()
dog.running()
dog.eating()

Dog.sleep()

image.png

继承内置类

我们也可以让我们的类继承自内置类,比如Array:
image.png

类的混入mixin

  • JavaScript的类只支持单继承:也就是只能有一个父类
    • 那么在开发中我们我们需要在一个类中添加更多相似的功能时,应该如何来做呢?
    • 这个时候我们可以使用混入(mixin);
  • image.png

JavaScript中的多态

  • 面向对象的三大特性:封装、继承、多态。
    • 前面两个我们都已经详细解析过了,接下来我们讨论一下JavaScript的多态。
  • JavaScript有多态吗?
    • 个人的总结:不同的数据类型进行同一个操作,表现出不同的行为,就是多态的体现。
    • 那么从上面的定义来看,JavaScript是一定存在多态的。
    • image.png

字面量的增强

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
1.属性的增强
2.方法的增强
3.计算属性名的写法
*/

var name = "why"
var age = 18

var key = "address" + " city"

var obj = {
// 1.属性的增强
name,
age,

// 2.方法的增强
running: function() {
console.log(this)
},
swimming() {
console.log(this)
},
eating: () => {
console.log(this)
},

// 3.计算属性名
[key]: "广州"
}

obj.running()
obj.swimming()
obj.eating()

function foo() {
var message = "Hello World"
var info = "my name is why"

return { message, info }
}

var result = foo()
console.log(result.message, result.info)

解构

  • ES6中新增了一个从数组或对象中方便获取数据的方法,称之为解构Destructuring。
    • 解构赋值 是一种特殊的语法,它使我们可以将数组或对象“拆包”至一系列变量中。
  • 我们可以划分为:数组的解构和对象的解构。
  • 数组的解构:
    • 基本解构过程
    • 顺序解构
    • 解构出数组:…语法
    • 默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var names = ["abc", "cba", undefined, "nba", "mba"]


// 1.数组的解构
// var name1 = names[0]
// var name2 = names[1]
// var name3 = names[2]
// 1.1. 基本使用
var [name1, name2, name3] = names
console.log(name1, name2, name3)

// 1.2. 顺序问题: 严格的顺序
var [name1, , name3] = names
console.log(name1, name3)

// 1.3. 解构出数组
var [name1, name2, ...newNames] = names
console.log(name1, name2, newNames)

// 1.4. 解构的默认值
var [name1, name2, name3 = "default"] = names
console.log(name1, name2, name3)
  • image.png
  • 对象的解构:
    • 基本解构过程
    • 任意顺序
    • 重命名
    • 默认值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
// 2.对象的解构
var obj = { name: "why", age: 18, height: 1.88 }
// var name = obj.name
// var age = obj.age
// var height = obj.height
// 2.1. 基本使用
var { name, age, height } = obj
console.log(name, age, height)

// 2.2. 顺序问题: 对象的解构是没有顺序, 根据key解构
var { height, name, age } = obj
console.log(name, age, height)


// 2.3. 对变量进行重命名
var { height: wHeight, name: wName, age: wAge } = obj
console.log(wName, wAge, wHeight)

// 2.4. 默认值
var {
height: wHeight,
name: wName,
age: wAge,
address: wAddress = "中国"
} = obj
console.log(wName, wAge, wHeight, wAddress)

// 2.5. 对象的剩余内容
var {
name,
age,
...newObj
} = obj
console.log(newObj)


// 应用: 在函数中(其他类似的地方)
function getPosition ({ x, y }) {
console.log(x, y)
}

getPosition({ x: 10, y: 20 })
getPosition({ x: 25, y: 35 })

function foo (num) { }

foo(123)

image.png