什么是面向对象
面向对象就是说,使用对象的时候,你可以直接使用它所提供的功能而忽略其内部组成情况。比如说,你家里的电视机,你使用了遥控,就能操作电视机,但是你实际上不知道这台电视机里面是什么零件组成的,你只要知道,我拿到遥控就可以操作电视机就好了。这就是一种面向对象的思想。
面向对象和面向过程的区别
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙某个事物在整个解决问题的步骤中的行为。
面向对象的特征
- 封装性
封装指的是隐藏内部的实现细节,只对外开放操作接口。接口就是对象的方法,无论对象的内部多么复杂,用户只需知道这些接口怎么使用即可。 - 继承性
继承是指个对象继承另一个对象的成员, 从而在不改变另一 个对象的前提下进行扩展 - 多态性
多态指的是同一个操作作用于不同的对象,会产生不同的执行结果。实际上JavaScript被设计成一种弱类型语言(即一个变量可以存储任意类型的数据),就是多态性的体现。例如,数字、数组、函数都有toString()方法,当使用不同的对象调用该方法时,执行结果不同,示例代码如下:
var obj=123;
console.log(obj.toString());//输出结果:123
obj=[1,2,3];
console.log(obj.toString());//输出结果:1,2,3
obj=funcation(){};
console.log(obj.toString());//输出结果:funcation(){}
JavaScript 定义了 5 种原始数据类型:
string
number
boolean
null
undefined
对象定义的两种方式
1.字面量的方式进行定义
var person = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
2.使用 {} 进行定义
var person = {};
person.name = "Tom ";
person.sex = " man";
person.age = 19;
person.run = function(){
console.log("一天跑一公里");
}
JavaScript 对象构造器
function Person(first, last, age, eye) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eye;
}
用大写首字母对构造器函数命名,以上函数 Person() 就是对象构造器函数
通过 new 关键词调用构造器函数可以创建相同类型的对象:
var myFather = new Person("Bill", "Gates", 62, "blue");
var myMother = new Person("Steve", "Jobs", 56, "green");
使用 prototype 属性
JavaScript prototype 属性允许您为对象构造器添加新属性:
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.nationality = "English";
JavaScript prototype 属性也允许您为对象构造器添加新方法
function Person(first, last, age, eyecolor) {
this.firstName = first;
this.lastName = last;
this.age = age;
this.eyeColor = eyecolor;
}
Person.prototype.name = function() {
return this.firstName + " " + this.lastName;
};
JavaScript 对象方法
// 添加或更改对象属性
Object.defineProperty(object, property, descriptor)
// 以数组返回所有可枚举的属性
Object.keys(object)
// 以数组返回所有属性
Object.getOwnPropertyNames(object)
JavaScript 对象原型
原型继承
原型继承:每一个构造函数都有prototype原型属性,通过构造函数创建出来的对象都继承自该原型属性。所以可以通过更改构造函数的原型属性来实现继承。
JavaScript 对象都从原型继承属性和方法
日期对象继承自 Date.prototype。数组对象继承自 Array.prototype。Person 对象继承自 Person.prototype
Object.prototype 位于原型继承链的顶端
日期对象、数组对象和 Person 对象都继承自 Object.prototype
1.简单混入继承
直接遍历一个对象,将所有的属性和方法加到另一对象上
var person = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
var child = {};
for (var k in person){
child[k] = person[k]
}
console.log(child)//打印的对象和person一样
2.混入式原型继承
混入式原型继承其实与上面的方法类似,只不过是将遍历的对象添加到构造函数的原型上。
var person = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
function Child(){
this.weight = 50;
}
for (var k in person){
Child.prototype[k]= person[k]
}
var p1 = new Child();
var p2 = new Child();
var p3 = new Child();
console.log(p1.name)//Tom
console.log(p2.sex)//man
console.log(p3.age)//19
面向对象思想封装一个原型继承
可以利用面向对象的思想,将面向过程进行封装。
function Child(){
this.weight = 50;
}
//给构造函数Child添加一个方法 extend
Child.prototype.extend = function (obj){
for (var k in obj){
this[k]= obj[k]
}
}
//调用 extend 方法
Child.prototype.extend({
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
})
3.替换式原型继承
替换式原型继承,其实就是将一个构造函数的原型对象替换成另一个对象。
function Child(){
this.weight = 50;
}
var person = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
Child.prototype = person
var p1 = new Child();
var p2 = new Child();
var p3 = new Child();
console.log(p1.name)//Tom
console.log(p2.sex)//man
console.log(p3.age)//19
这样做会产生一个问题,就是替换的对象会重新开辟一个新的空间。替换原型对象的方式会导致原型的constructor的丢失,constructor属性是默认原型对象指向构造函数的,就算是替换了默认原型对象,这个属性依旧是默认原型对象指向构造函数的,所以新的原型对象是没有这个属性的。
解决方法:手动关联一个constructor属性
function Child(){
this.weight = 50;
}
var person = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
//给需要替换的对象添加一个 constructor 属性 指向原本的构造函数
person.constructor = Child;
//将一个构造函数的原型对象替换成另一个对象
Child.prototype = person;
var p1 = new Child();
console.log(p1.__proto__.constructor === Child)//true
4.Object.create()方法实现原型继承
当我们想把对象1作为对象2的原型的时候,就可以实现对象2继承对象1。前面我们了解了一个属性:proto,实例出来的对象可以通过这个属性访问到它的原型,但是这个属性只适合开发调试时使用,并不能直接去替换原型对象。所以这里介绍一个新的方法:Object.create()。
语法:
var obj1 = Object.create(原型对象);示例代码: 让空对象obj1继承对象obj的属性和方法
var person = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
var abj1 = Object.create(person)
console.log(abj1.name)//Tom
abj1.run()//一天跑一公里
兼容性:
由于这个属性是ECMAScript5的时候提出来的,所以存在兼容性问题。
利用浏览器的能力检测,如果存在Object.create则使用,如果不存在的话,就创建构造函数来实现原型继承。
function create(person){
if(Object.create){
return Object.create(person);
}else{
function Fun(){}
Fun.prototype = person
return new Fun();
}
}
var person = {
name: "Tom ",
sex: " man",
age:19,
run:function(){
console.log("一天跑一公里");
}
}
var abj1 = create(person)
console.log(abj1.name)//Tom
abj1.run()//一天跑一公里
call()/apply()方法
function Teacher(name,age){
this.name = name;
this.age = age;
this.sayhi = function(){
console.log('name:'+name+", age:"+age);
}
}
function Student(){
var args = arguments;
Teacher.call(this,args[0],args[1]);
// Teacher.apply(this,arguments);
}
var teacher1 = new Teacher('xiaoming',23);
teacher1.sayhi();
var student1 = new Student('xiaolan',12);
student1.sayhi();
// console.log: name:xiaoming, age:23
// console.log: name:xiaolan, age:12