BCSP-玄子前端开发之JavaScript+jQuery入门CH06_JavaScript面向对象
4.6 对象
4.6.1 什么是对象
对象是相关属性和方法的集合体
- 属性
- 方法
String对象
- length 属性
- indexOf()
- replace() 方法
Array对象
- length 属性
- sort()
- concat()
- join() 方法
Date对象
- get×××:获取年、月、日、时、分、秒等等
- set×××:设置年、月、日、时、分、秒等等
Math对象
- round()
- max()
- min() 方法
Boolean对象
- toString() 方法
RegExp对象
- compile()
- exec()
- test() 方法
4.6.2 创建对象
- 内置对象
- 自定义对象
4.6.3 创建常见内置对象
String 对象
- 字符串
- new String()
Date 对象
- new Date()
Array 对象
- [ element0, element1, …, elementN ]
- new Array()
Math 对象
- 所有属性和方法都是静态的
Boolean 对象
- new Boolean()
RegExp 对象
- new RegExp()
4.6.4 创建自定义对象
基于Object对象创建自定义对象
var 对象名称 = new Object();
通过点操作符(.)为其添加属性和方法
var student = new Object();
student.name = "张三";
student.age = 18;
student.email = "zhangsan@163.com";
student.hobby = "打球";
student.showName = function() { alert( this.name ); }
student.showName();
使用字面量赋值方式创建自定义对象
var student = {
name : "张三",
age : 18,
email : "zhangsan@163.com",
hobby : "打球",
showName : function() {
alert( this.name );
}
}
student.showName();
4.7 简单工厂模式
基于Object对象或使用字面量创建对象,如需批量创建对象,会产生大量重复代码
使用简单工厂模式封装对象的创建逻辑
- 模式是指在某一环境下某个问题的一种解决方案
- 简单工厂模式是一种用来创建对象的软件设计模式
4.7.1 演示
将对象的创建逻辑封装在一个函数中
function createStudent( name, age, email, hobby ) {
var p = new Object();
p.name = name;
……
p.showName = function() { alert( this.name ); }
return p;
}
使用工厂函数创建对象
var person1 = createStudent("张三", 18, "zhang3@163.com", "打球");
person1.showName();
var person2 = createStudent("李四", 19, "lisi@163.com", "看书");
person2.showName();
4.8 构造函数
前述创建对象的方法无法区分不同类型的对象
4.8.1 定义构造函数
用以创建特定类型的对象
function Student( name, age, email, hobby ) {
this.name = name;
……
this.showName = function() { alert(this.name); }
}
4.8.2 与工厂函数相比
- 没有显式创建Object对象,没有return语句
- 将属性和方法赋给this对象
4.8.3 使用构造函数创建对象
var stu1 = new Student( "张三", 18, "zhangsan@163.com", "打球" );
stu1.showName();
var stu2 = new Student( "李四", 19, "lisi@163.com", "看书" );
stu2.showName();
4.8.4 构造函数执行过程
构造函数执行过程中会经历以下4个步骤
- 创建一个新对象
- 将构造函数的作用域赋给新对象,因此this就指向了这个新对象
- 执行构造函数中的代码,为这个新对象添加属性及方法
- 返回新对象
4.8.5 constructor属性和
对象中包含constructor属性,指向其构造函数
alert( stu1.constructor == Student ); // 结果为true
alert( stu2.constructor == Student ); // 结果为true
4.8.6 instanceof操作符
使用instanceof操作符检测对象类型
alert( stu1 instanceof Student ); // 结果为true
alert( stu2 instanceof Student ); // 结果为true
stu1和stu2同是Object类型,所有对象都继承自Object
alert( stu1 instanceof Object ); // 结果为true
alert( stu2 instanceof Object ); // 结果为true
4.8.7 构造函数问题分析
构造函数的定义方式会导致showName()方法在每个实例上都要重新创建一遍
function Student( name, age, email, hobby ) {
……
this.showName = function() { alert(this.name); }
}
通过函数定义的方式把showName()方法转移到构造函数的外部,所有实例共享全局作用域中定义的同一个showName()函数
function Student( name, age, email, hobby ) {
……
this.showName = showName
}
function showName() { alert(this.name); }
全局函数实际上仅为某个对象调用,全局函数破坏了自定义类型的封装性
4.9 原型对象
每个函数都有一个prototype属性,指向其原型对象
使用原型对象方式添加属性和方法,所有实例会共享它所包含的属性和方法
构造函数名.prototype.属性或方法
function Student() {}
Student.prototype.name = "张三";
……
Student.prototype.showName = function() { alert(this.name); };
……
当实例读取某个属性时
- 首先在实例本身开始搜索,找到则返回
- 如没有找到,则继续在原型对象中查找
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-59hCbbw2-1682304866455)(./assets/image-20230423214211000.png)]
4.10 继承
- 原型链
- 对象继承
4.10.1 原型链
一个类型的实例是另一个类型的原型对象,相关的原型对象层层递进,构成了实例与原型的链条,即原型链
function Person() { this.foot = 2; }
Person.prototype.getFoot = function() { return this.foot; }
function Woman() { this.head = 1; }
Woman.prototype = new Person();
// 继承了Person
Woman.prototype.getHead = function() { return this.head; }
var woman1 = new Woman();
alert(woman1 instanceof Woman); //true
alert(woman1 instanceof Person); //true
alert(woman1 instanceof Object); //true
alert(woman1.getFoot()); //2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ck5uG8DX-1682304866458)(./assets/image-20230423214422125.png)]
woman1调用getFoot()的步骤
- 搜索实例
- 搜索Woman.prototype
- 搜索Person.prototype
搜索的过程要一环一环地前行到原型链的末端才会停下来
4.10.2 完整的原型链
所有函数的默认原型都是Object对象的实例
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTDUxUOj-1682304866458)(./assets/image-20230423214512202.png)]
4.10.3 方法重写
子类型可以通过prototype对象重写父类型中的方法
function Person() { this.foot = 2; }
Person.prototype.getFoot = function() { return this.foot; }
function Woman() { this.head = 1; }
Woman.prototype = new Person();
Woman.prototype.getHead = function() { return this.head; }
Woman.prototype.getFoot = function() { return false; }
……
4.11 对象继承
function Person() {
this.skinColor = [ "black", "white" ]; // 肤色
}
function Woman() {}
Woman.prototype = new Person(); // 继承了Person
var woman1 = new Woman();
woman1.skinColor.push( "yellow" );
alert(woman1.skinColor); // 输出什么?
var woman2 = new Woman();
alert(woman2.skinColor); // 输出什么?
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xro1zHPd-1682304866458)(./assets/image-20230423214607121.png)]
问题1:两个实例输出的信息一样,为什么?
问题2:创建子类型的实例时,不能向父类型的构造函数中传参
4.11.1 借用构造函数
借用构造函数又被称为伪造对象或经典继承,指在子类型构造函数的内部调用父类型的构造函数
应用某一对象的一个方法,用另一个对象替换当前对象
apply( [ thisOjb [, argArray ]] )
调用一个对象的一个方法,以另一个对象替换当前对象
call( [ thisObj [, arg1 [, arg2 [, … [, argN ]]]]] )
function Person() {
this.skinColor = [ "black", "white" ]; // 肤色
}
function Woman() {
Person.call(this); // 也可以使用apply()方法
// 继承了Person
}
var woman1 = new Woman();
woman1.skinColor.push( "yellow" );
alert(woman1.skinColor); // 输出什么?
var woman2 = new Woman();
alert(woman2.skinColor); // 输出什么?
借用构造函数可以在子类型构造函数中向父类型构造函数传参
function Person(name) {
this.name = name;
}
function Woman(){
Person.call( this, "amy" );
this.age = 18;
}
……
为了确保父类型构造函数不会重写子类型的属性,可以在调用父类型构造函数后再添加应该在子类型中定义的属性
4.11.2 组合继承
组合继承也叫做伪经典继承
- 将原型链和借用构造函数的技术组合到一块,融合二者的优点并规避二者的缺陷,是JavaScript开发中最常用的一种继承模式
- 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承
- 既实现了函数复用,又能够保证每个实例都有自己的属性
function Person(name) {
this.name = name;
this.skinColor = [ "black", "white" ]; // 肤色
}
Person.prototype.sayName = function () { alert(this.name); }
function Woman(name, age) {
Person.call(this, name); // 继承属性
this.age = age;
}
Woman.prototype = new Person(); // 继承方法
Woman.prototype.sayAge = function () { alert(this.age); }
……
BCSP-玄子前端开发之JavaScript+jQuery入门CH06_JavaScript面向对象