面向对象

本节主要讲述面向对象

创建对象

工厂模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function createPerson(name, age, job) {
var obj = new Object();

obj.name = name;
obj.age = age;
obj.job = job;

obj.sayName = function() {
alert(this.name)
}


return obj
}

var person = createPerson("QIan", 12, "do")

person.sayName();

构造函数模式

1
2
3
4
5
6
7
8
9
10
11
12
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;

this.sayName = function() {
alert(this.name)
}
}

var person = new Person("Qian", 12, "do")
person.sayName();

创建实例的4个步骤

  • 创建一个新对象
  • 将构造函数的作用域付给新对象(因此this就指向了这个新对象)
  • 执行构造函数中的代码(为这个新对象添加属性)
  • 返回新对象

原型

理解原型对象

  • 创建一个新函数,就会为该函数创建一个prototype属性,这个属性就是指向函数的原型对象
  • 所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针
  • new出来的实例,包含一个内部属性,该属性仅仅指向Person.prototype
  • 也就是说实例和构造函数没有关系

获取实例的[[prototype]]

isPrototypeOf()

Object.getPrototypeOf()

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person() {}

Person.prototype.name = "Qian";
Person.prototype.sayName = function() {
console.log(this.name)
}

var p1 = new Person();
p1.sayName();

console.log(Person.prototype.isPrototypeOf(p1))

console.log(Object.getPrototypeOf(p1) == Person.prototype)

Object.getPrototypeOf()可以方便的取得一个对象的原型

读取属性

  • 每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性
  • 搜素首先从对象实例本身开始
  • 实例没有就搜索原型对象

检测属性的来源(实例或者原型)

hasOwnProperty

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function Person() {}

Person.prototype.name = "Qian";
Person.prototype.sayName = function() {
console.log(this.name)
}

var p1 = new Person();
var p2 = new Person();

p1.sayName();
p2.name = "Blue"

console.log(p1.hasOwnProperty("name")) //false
console.log(p2.hasOwnProperty("name")) //true
  • 来自实例就返回true
  • 来自原型就返回false

in操作符

无论该属性存在与实例还是存在于原型中,都会返回true

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Person() {}

Person.prototype.name = "Qian";
Person.prototype.sayName = function() {
console.log(this.name)
}

var p1 = new Person();
var p2 = new Person();

p1.sayName();
p2.name = "Blue"

console.log(p1.hasOwnProperty("name")) /* false */
console.log(p2.hasOwnProperty("name")) /* true */

console.log('name' in p1) /* true */
console.log('name' in p2) /* true */

获取所有可枚举的实例属性(Object.keys())

Object.keys()接受一个对象作为参数,返回一个包含所有可枚举属性的字符串数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function Person() {}

Person.prototype.name = "Qian";
Person.prototype.sayName = function() {
console.log(this.name)
}

var p1 = new Person();
var p2 = new Person();

p2.name = "Blue"
p2.age = 12


var keys = Object.keys(Person.prototype)
console.log(keys)

console.log(p2)

原型写法

1
2
3
4
5
6
7
8
9
10
function Person() {}

Person.prototype = {
constructor: Person,
name: "Qian",
age: 28,
sayName: function() {
console.log(this.name);
}
}

原型的动态性

对原型对象所做的任何修改都能够从实例上反映出来

1
2
3
4
5
6
7
var friend = new Person();

Person.prototype.sayHi = function() {
console.log("Hi")
}

friend.sayHi();

原生对象的原型

所有原生引用类型(Object、Array、String)等

1
2
3
4
5
6
String.prototype.startsWith = function(text) {
return this.indexOf(text) == 0
}

var msg = "Hello world";
console.log(msg.startsWith('Hello')) /* true */

组合使用构造函数模式和原型模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
}

Person.prototype = {
constructor: Person,
sayName: function() {
console.log(this.name)
}
}

var p1 = new Person("Qian", 23, "Do")

p1.sayName() /* Qian */

继承

原型继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* 构造函数 */
function SuperType() {
this.property = true;
}
/* 原型添加方法 */
SuperType.prototype.getSuperValue = function() {
return this.property;
}
/* 构造函数 */
function SubType() {
this.subprotperty = false;
}
/* 继承SuperType对象 */
SubType.prototype = new SuperType()

var instance = new SubType();
console.log(instance.getSuperValue()) /* true */

SubType继承了SuperType,而继承是通过创建SuperType的实例,并将实例付给SupType.prototype实现的

构造函数继承

通过call()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person() {
this.name = "Qian",
this.sayName = function() {
console.log(this.name)
}
}

function Parent() {
Person.call(this)
}

var p1 = new Parent()
p1.sayName() /* Qian */

传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
function Person(name) {
this.name = name,
this.sayName = function() {
console.log(this.name)
}
}

function Parent() {
Person.call(this, "Blue")
}

var p1 = new Parent()
p1.sayName() /* Blue */

判断对象类型

  • 可以通过 Object.prototype.toString.call(xx)。这样我们就可以获得类似 [object Type]的字符串。

  • instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype

方法

1
2
3
function type(obj) {
return typeof obj !== "object" ? typeof obj : Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}