创建对象
1.字面量
var people = {
age: 20,
name: '小张',
setName: function (name) {
this.name = name;
}
}
//使用方式
console.log(people.name)
people.setName("小赵")
适用于创建初始数据确定的对象,但是当创建多个对象时,代码重复率过高。
2.工厂模式
function createPeople(name, age) {
var obj = {
name,
age,
setName: function (name) {
this.name = name;
}
}
return obj
}
//使用方式
var p1 = createPeople('小张', 20)
var p2 = createPeople('小赵', 20)
解决了创建多个对象代码重复率过高的问题,但是由此创建的对象无具体类型,都是Object类型
3.构造函数
//Object构造函数模式
var people = new Object();
people.name = "小张";
people.age = 20;
people.setName = function (name) {
this.name = name;
}
//使用方式
console.log(people.name);
people.setName('小赵');
适用于起始不确定对象里面的内容时,但是语句较多。
//自定义构造函数
function People(name, age) {
this.name = name;
this.age = age;
this.setName = function (name) {
this.name = name;
}
}
//使用方式
var p1 = new People('小张', 20);
p1.setName('小赵');
解决了创建对象无具体类型的问题,但是创建多个对象会浪费内存。
(创建了多个函数对象setName(),就开辟了多个空间,虽然对象指向不同地址,但是地址内容都是重复的,造成内存浪费)
4.原型
function People() {}
People.prototype = {
constructor: People,
name: '小张',
age: 20,
setName: function (name) {
this.name = name;
}
}
//使用
var p = new People()
p.constructor.prototype.name = '小赵'
解决了自定义构造函数中函数对象复用的问题,但是一个实例对原型属性的修改会影响到其它实例
5.组合模式(原型+构造)
function People(name, age) {
this.name = name;
this.age = age;
}
People.prototype.setName = function (name) {
this.name = name;
}
//使用
var p = new People('小张', 20)
p.setName('小赵')
解决了各自的缺点,构造函数初始化对象属性,原型实现函数方法的复用,但是代码封装性不好
6.动态原型
function People(name, age) {
this.name = name;
this.age = age;
if (typeof this.setName !== 'function') {
People.prototype.setName = function (name) {
this.name = name;
}
}
}
解决了组合模式封装性差的问题
7.寄生构造模式
function People(name, age) {
var obj = {
name,
age,
setName: function (name) {
this.name = name;
}
}
return obj
}
//使用方式
var p1 = new People('小张', 20)
var p2 = new People('小赵', 20)
除了使用方式与工厂模式不同,其它一样
继承方式
1.原型链
function People(name) {
this.name = name;
}
People.prototype.addAge = function (age) {
this.age = age;
}
function Student(name, grade) {
this.grade = grade;
}
Student.prototype = new People(); // 子类型的原型为父类型的一个实例对象
Student.prototype.constructor = Student; // 让子类型的原型的constructor指向子类型
var xiaoZhang = new Student('小张', 60);
xiaoZhang.addAge(20);
缺点:包含引用类型时,会被所有实例共享,改动将影响所有实例,且不能向父类传递参数。
2.构造函数
function People(name) {
this.name = name;
this.setName = function (name) {
this.name = name;
}
}
People.prototype.addAge = function (age) {
this.age = age;
}
function Student(name, grade) {
People.call(this, name);
this.grade = grade;
}
var xiaoZhang = new Student('小张', 60);
xiaoZhang.setName('小赵')
// xiaoZhang.addAge(20) //报错
解决了不能向父类传递参数缺点,但是跟创建对象中构造函数模式问题一样,无法实现函数方法复用,并且父类原型上的方法对子类不可见。
3.组合模式(原型链+构造)
function People(name) {
this.name = name;
}
People.prototype.addAge = function (age) {
this.age = age;
}
function Student(name, grade) {
People.call(this, name); //第一次调用
this.grade = grade;
}
Student.prototype = new People(); //第二次调用
Student.prototype.constructor = Student;
var xiaoZhang = new Student('小张', 60);
xiaoZhang.addAge(20);
组合模式解决了两者单独使用的缺点,但是缺点是调用了两次父类的构造函数。
4.原型式继承
function People(obj) {
function Student() {
this.name = obj.name;
this.setName = function (name) { //无法被复用的函数,练习使用
this.name = name;
}
}
Student.prototype = obj;
return new Student();
}
var student = {
name: '小张',
addAge: function (age) {
this.age = age;
}
}
var new_student = People(student)
new_student.addAge(20);
new_student.setName('小赵');
原型式继承只是对某个对象实现一种简单继承,缺点同原型链继承。
5.寄生式继承(原型式+工厂)
function People(obj) {
function Student() {
this.name = obj.name;
this.setName = function (name) {
this.name = name;
}
}
Student.prototype = obj;
return new Student();
}
function createStudent(obj){
var clone = People(obj);
clone.addAge = function(age){ //扩展对象,但无法实现复用
this.age = age;
}
return clone;
}
var student = {
name:'小张',
}
var new_student = createStudent(student);
new_student.addAge(20);
new_student.setName('小赵');
优点:可以为对象进行扩展。缺点:同原型式继承一样,且扩展函数无复用。
6.寄生式组合继承
function People(name) {
this.name = name;
}
People.prototype.addAge = function (age) {
this.age = age;
}
function Student(name, grade) {
People.call(this, name); //仅一次调用
this.grade = grade;
}
Student.prototype = Object.create(People.prototype); //关键的一行
Student.prototype.constructor = Student;
var xiaoZhang = new Student('小张', 60);
xiaoZhang.addAge(20);
使用父类原型的副本作为子类原型,避免了调用了两次父类的构造函数。
如有不正,请批评指正......
试着自己写一遍后发现,我真的会谢。。。