JS面向对象编程
前言
Java ,JS 都是面向对象编程语言,但是它们的语法有重大区别。
Java 中有关键字 class ,用于定义类型。
JS 中没有定义类型的关键字,而是使用函数作为类,准确的说JS是基于原型的语言。
一、JS面向对象基础用法
// 相当于构造方法的函数
function makePerson(first, last) {
return {
first: first,
last: last
};
}
// 相当于功能方法
function personFullName(person) {
return person.first + ' ' + person.last;
}
// 相当于功能方法
function personFullNameReversed(person) {
return person.last + ', ' + person.first;
}
//相当于创建对象
var s = makePerson('Simon', 'Willison');
//相当于调用功能方法
personFullName(s); // "Simon Willison"
//相当于调用功能方法
personFullNameReversed(s); // "Willison, Simon"
这种方式定义了太多函数,太丑陋了。
二、JS面向对象一般用法
因为JS中函数也是对象,所以可以将函数附加到对象中。
function makePerson(first, last) {
return {
first: first,
last: last,
//功能方法
fullName: function() {
return this.first + ' ' + this.last;
},
//功能方法
fullNameReversed: function() {
return this.last + ', ' + this.first;
}
};
}
var s = makePerson('Simon', 'Willison');
//调用功能方法
s.fullName(); // "Simon Willison"
s.fullNameReversed(); // "Willison, Simon"
注意this关键字,指向当前对象。
如果使用一个对象 obj 的 . 或 [] 操作符调用该函数,this 就是 obj 。
如果没有用 . 或 [] 调用该函数, this 就是 global。
var s = makePerson('Simon', 'Willison');
var fullName = s.fullName;
fullName(); // undefined undefined 此处 this是 global,而global没有 first和last变量。
三、JS面向对象二般用法
掌握 this 的使用,可以更进一步优化代码:
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = function() {
return this.first + ' ' + this.last;
};
this.fullNameReversed = function() {
return this.last + ', ' + this.first;
};
}
var s = new Person('Simon', 'Willison');
这种方式也存在问题:
创建每一个实例对象时,都会创建 fullName 和 fullNameReversed 函数对象,创建太多的函数对象,造成空间浪费。
四、JS面向对象三般用法
function personFullName() {
return this.first + ' ' + this.last;
}
function personFullNameReversed() {
return this.last + ', ' + this.first;
}
function Person(first, last) {
this.first = first;
this.last = last;
this.fullName = personFullName;
this.fullNameReversed = personFullNameReversed;
}
功能函数只创建了一次,创建实例对象时,没有重新创建功能函数,只是都引用了创建好的函数,节省了空间。
五、JS面向对象四般用法 - 原型
使用原型 prototype
function Person(first, last) {
this.first = first;
this.last = last;
}
Person.prototype.fullName = function() {
return this.first + ' ' + this.last;
};
Person.prototype.fullNameReversed = function() {
return this.last + ', ' + this.first;
};
Person.prototype 叫做 Person 的原型,它也是一个对象,共享给Person的所有实例使用。
prototype 组成了一个查询链,叫 “原型链”:
任意时刻访问Person的一个不存在属性时,JS都会去检查 Person.prototype 中有没有这个属性。
注意:分配给 Person.prototype 的数据将共享给它的所有实例对象 。
prototype 是一个非常强大的特性,可以在任何时候修改 prototype ,运行时给已有对象添加额外方法。
var s = new Person('Simon', 'Willison');
s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function
Person.prototype.firstNameCaps = function() {
return this.first.toUpperCase();
};
s.firstNameCaps(); // "SIMON"
神奇的是,JS的内建对象也可以通过 prototype 添加额外数据。
var s = 'Simon';
s.reversed(); // TypeError on line 1: s.reversed is not a function
String.prototype.reversed = function() {
var r = '';
for (var i = this.length - 1; i >= 0; i--) {
r += this[i];
}
return r;
};
s.reversed(); // nomiS
reversed 函数对String字面量也可用了
'This can now be reversed'.reversed(); // desrever eb won nac sihT
六、原型链
prototype 原型模式构成了原型链,原型链的顶点是 Object.prototype。
比如说 Object.prototype 中拥有 toString() 函数,当获取对象表达式时会调用 toString() 函数。
var s = new Person('Simon', 'Willison');
s.toString(); // [object Object]
Person.prototype.toString = function() {
return '<Person: ' + this.fullName() + '>';
}
s.toString(); // "<Person: Simon Willison>"
七、apply 和 call 函数
// func 是一个函数对象
// obj 将会作为 this 使用
// args 是调用 func 时传入的参数
func.apply(obj,args)
apply 的用法有点像 java 的反射,对象.方法 -> 方法.对象 。
// trivialNew用来模拟 new,但它不构造原型链,不能代替 new
function trivialNew(constructor, ...args) {
var o = {}; // Create an object
constructor.apply(o, args);
return o;
}
var bill = trivialNew(Person, 'William', 'Orange');
// 等价于
var bill = new Person('William', 'Orange');
apply 与 call 是一个姐妹函数,call 函数将展开表达式替换成了一个数组
// func 是一个函数对象
// obj 将会作为 this 使用
// argsArr 是调用 func 时传入的参数数组
func.call(obj,argsArr)
function lastNameCaps() {
return this.last.toUpperCase();
}
var s = new Person('Simon', 'Willison');
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps(); // WILLISON
八、new 关键字
new 与 this 有很强的联系。
// 1、new 先创建了一个空对象 {}
// 2、调用 Person()函数,this 设置给 创建的 {} 对象
// 3、Person()函数不返回值,作用仅仅是对 this 即 {} 进行修改
// 4、new 关键字返回 this 引用
var s = new Person('Simon', 'Willison');
用 new 关键字调用的函数叫做构造函数,构造函数通常首字母大写,用来提示人们使用 new 来调用。