分享人:郭晨阳
目录
1.背景介绍
2.知识剖析
3.常见问题
4.解决方案
5.编码实战
6.扩展思考
7.参考文献
8.更多讨论
起源:Simula67语言
对象:“无序属性的结合,其属性值可以包含基本值、对象或者函数”。
面向对象编程(OOP):核心思想是将各种复杂关系,抽象成一个个对象,然后由对象之间的分工合作,完成对真实世界的模拟。
原型对象:只要创建一个新函数,就会根据特定的规则为该函数创建一个prototype属性指向其原型对象,默认情况下原型对象会自动获得一个constructor属性,该属性包含一个指向prototype属性所在函数的指针
Function.prototype.constructor===Function //true
构造函数:本身是一个函数,出于创建特定类型新对象的目的而定义的,内部使用this变量,需要和new配合使用来创建实例,this变量会绑定在实例对象上。
封装模式:将“属性”和“方法”封装成对象的模式,即创建对象的方式
1.Object构造函数或对象字面量创建
var Cat = {
name : '',
color : ''
}
根据该对象的规格封装,生成两个实例对象
var cat1 = {}; // 创建一个空对象
cat1.name = "大毛"; // 按照原型对象的属性赋值
cat1.color = "黄色";
var cat2 = {};
cat2.name = "二毛";
cat2.color = "黑色";
原始模式的改进
function Cat(name,color) {
return {
name:name,
color:color
}
}
var cat1 = Cat("大毛","黄色");
var cat2 = Cat("二毛","黑色");
构造函数模式
function Cat(name,color){
this.name=name;
this.color=color;
}
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.name); // 大毛
alert(cat1.color); // 黄色
这是cat1、cat2会自动含有一个constructor属性,指向构造函数
构造函数方法很好用,但是存在一个浪费内存的问题
function Cat(name,color){
this.name = name;
this.color = color;
this.type = "猫科动物";
this.eat = function(){alert("吃老鼠");};
}
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat ("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
prototype模式
function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype.type = "猫科动物";
Cat.prototype.eat = function(){alert("吃老鼠")};
var cat1 = new Cat("大毛","黄色");
var cat2 = new Cat("二毛","黑色");
alert(cat1.type); // 猫科动物
cat1.eat(); // 吃老鼠
最常见方式,组合使用构造函数与原型模式
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["Shelby", "Court"];
}
Person.prototype = {
constructor : Person,
sayName : function(){
alert(this.name);
}
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor");
person1.friends.push("Van");
alert(person1.friends); //"Shelby,Count,Van"
alert(person2.friends); //"Shelby,Count"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
继承概念
许多OO语言都支持两种继承方式:接口继承和实现继承,接口继承只继承方法签名,实现继承则继承实际的方法
js如何实现继承?
比如现在有一个动物对象的构造函数:
function Animal(){
this.species = "动物";
}
现在有一个猫的构造函数
function Cat(name,color){
this.name = name;
this.color = color;
}
prototype模式
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物
主要的问题是包含引用类型的值的原型属性会被所有实例共享无
法独立修改,并且无法想超类型中的构造函数传参。
构造函数绑定
function Cat(name,color){
Animal.apply(this, arguments);
this.name = name;
this.color = color;
}
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物
主要的问题是如果有公用方法属性,会都被实例化,浪费内存
直接继承prototype
function Animal(){ }
Animal.prototype.species = "动物";
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黄色");
alert(cat1.species); // 动物
缺点是任何对Cat.prototype的修改都会反应到Animal.prototype,
并且Animal.prototype.constructor也被改变了
利用空对象作为中介
var F = function(){};
F.prototype = Animal.prototype;
Cat.prototype = new F();
Cat.prototype.constructor = Cat;
F是空对象,几乎不占内存
ES6中JavaScript拥有类的概念了,参考java等语言思考JavaScript如何使用类来简化封装、继承。
参考:阮一峰的网络日志
参考:JavaScript高级程序设计第三版
通常在一般的项目里不需要,因为应用简单,但你要用纯js做一些复杂的工具或框架系统就要用到了,比如webgis、或者js框架如jquery、angular、vue什么的,不然一个几千行代码的框架不用继承得写几万行,甚至还无法维护
感谢大家观看
BY:郭晨阳