JavaScript - 面向对象与面向对象的发展过程
一、面向对象与面向过程
| 面向过程 c | 注重问题的解决 |
| 面向对象 JAVA | 完成对真实世界的模拟,把一个对象的共同特点抽离出现,有了所有的’属性’和’方法’ class |
js并不是一个真正的面向对象的语言 , js在模拟面向对象
对象的特点:属性 + 方法
对象在js里面是由构造函数new出来的
这里我们举个例子~:
问题1:有一只两岁的柯基
// 面向过程
const dog = '柯基' ;
const age = 2 ;
// 面向对象
const obj = {
dog : '柯基' ,
age : 2
}
问题2:又来了一只3岁的二哈
// 封装函数
function dog(type, age) {
console.log('有一只' + age + '岁的' + type);
}
dog('二哈', 3) //有一只3岁的二哈
// 面向对象
function Dog(type, age) {
const obj = {
dog: type,
age,
say: function() {
console.log('有一只' + this.age + '岁的' + this.dog);
}
}
return obj;
}
const d = Dog('二哈', 3);
console.log(d); //{dog: '二哈', age: 3, say: ƒ}
d.say() //有一只3岁的二哈
// 不会共享内存
console.log(d1.say === d2.say); //false
// d1也不是Dog生的
console.log(d1.constructor); //Object
二、其他对象
- 所有实例化的对象都共享方法
var arr1 = new Array();
var arr2 = new Array();
console.log(arr1.forEach == arr2.forEach); //true
//arr1与Array是母子关系 ,arr1是由Array生出来的
console.log(arr1.constructor); //ƒ Array() { [native code] }
三、JavaScript面向对象的发展过程
1.工厂模式:
定义:创建一个对象,给对象加工(添加属性和方法),返回这个对象
缺点:创建出来的对象跟函数没有任何关系;创建出来的对象之间的方法不共享
// 工厂模式
function dog(type , age) {
// 原材料 : 创建一个对象
const obj = {} ;
// 加工
obj.type = type ;
obj.age = age ;
obj.say = function () {
console.log('有一只' + obj.age + '岁的' + obj.type);
}
// 出厂:返回这个对象
return obj
}
const dog1 = dog('柯基' , 3) ;
2.构造函数模式
- 任何一个函数都有可能成为一个构造函数,只要有new就可以
构造函数模式与工厂模式有什么不同:
1.为了区分普通函数和构造函数,JavaScript建议构造函数使用大驼峰命名
2.没有显示的创建对象,最后也没有return语句:new操作符帮你创建对象并返回。
3.直接将属性和方法赋给了 this 对象:new操作符帮你把this指向创建的对象。
4.创建实例的时候需要用new操作符来调用构造函数。
5.可以用instanceof判断创建出的对象的类型。
function fn() {
console.log(this);
console.log(666);
}
var res = fn(); //this指向window
console.log(res); // 函数没有返回值 undefined
var res2 = new fn(); // this指向了对象
console.log(res2); // 返回了这个对象
- 总结 new的贡献:
1.创建了一个对象
2.this指向了这个对象
3.把这个对象的原型指向了构造函数的原型对象
4.返回了这个对象
- 构造函数虽然解决了关系问题,但是方法依然不共享。也就是说通过构造函数创建的每个实例对象里的属性都是独立的,包括一些本可以被共用的属性和方法。
- dog1和dog2的say方法虽然内容是一样的,却各自在内存里开辟了新的空间来存放两个内容一样的方法,造成了内存的浪费。这就违背了函数的复用原则。
function Dog(type, age) {
this.type = type;
this.age = age;
this.say = function() {
console.log('有一只' + this.age + '岁的' + this.type);
}
}
const dog1 = new Dog('柯基', 3);
const dog2 = new Dog('二哈', 4);
console.log(dog1.say == dog2.say); //输出:false 说明dog1和dog2方法不共享
3.原型模式
- prototype原型对象:提供共享的属性和方法
- 每个函数都有一个prototype属性,prototype的值指向其相对应的原型对象。而原型对象正是被设计来存放类的公有属性和方法的,它除了自带一个不可枚举的constructor属性指向函数本身外,和其他空对象并无不同。你可以把原型对象理解为一个共享仓库。
原型:任何一个对象都有原型 proto , 也就是这个构造函数
原型对象:任何一个函数都有原型对象 prototype 。作用:给所有的实例化对象提供共有的属性和方法
function Fn(type) {
this.type = type;
this.age = '1';
}
//prototype 原型对象:提供共享的属性和方法
Fn.prototype.species = '狗';
Fn.prototype.say = function() {
console.log('汪');
}
var dog1 = new Fn('二哈');
var dog2 = new Fn('柯基');
// 每一个实例化对象都共享say方法
console.log(dog1.say == dog2.say); //true
console.log(dog1.__proto__); //指向这个构造函数
console.log(dog1.constructor); //Fn
那原型对象是怎么做到被所有实例共享的呢?前面提到了new这个操作符,在js中new操作符其实也是个语法糖,那它在背后替我们做了什么呢?
//new到底做了什么
function _new(fn) {
return function() {
//1.创建一个对象
var obj = new Object;
//2.把创建的对象的原型(__proto__)指向构造函数的原型对象
obj.__proto__ = fn.prototype;
//3.使this指向该对象
var result = fn.apply(o, arguments);
//4.检测构造函数有无返回值,如有,则返回构造函数的返回值。否则返回创建的对象
if (result && (typeof result === 'object' || typeof result === 'function')) {
return result;
} else {
return obj;
}
}
}