JS如何创建对象和继承对象

JS创建对象的几种方法:工厂模式,构造函数模式,原型模式,混合模式,动态原型模式

 

1 在工厂模式中,在构造函数内部创建一个新对象,最后返回这个对象。当实例化时,我们不需要用new关键字,就像调用方法一样就可以实例化。

工厂模式的缺点是容易和普通函数混淆,只能通过命名来确认它是一个 构造函数。不推荐使用这种模式。

//factory pattern

function createPerson(name, age, job){
    var o = {};
    o.name = name;
    o.age = age;
    o.job = job;
    o.friends = ["Mike", "Sun"];
    o.sayName = function(){
        alert("factory pattern: " + this.name);
    }
    return o;
}

var Abby = createPerson("Abby", "22", "Softwarre Engineer");
Abby.sayName();

 

2 构造函数模式,用new关键字来实例化对象。与工厂方式相比,使用构造函数方式创建对象,无需在函数内部重新创建对象,而使用this指代,并且函数无需明确return。不推荐使用这种模式。

构造函数的缺点是不断的拷贝,每new一次就造出一个副本,每个方法都要在每个实例上重新创建一遍,显然这样是不行的,我们想要的是一种有些方法共享所有,有此方法私有,于是Eric发明了原型链。

//constructor pattern
function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function(){
        alert("constructor pattern: " + this.name);
    }
}

var Abby = new Person("Abby", "22", "Software Engineer");
Abby.sayName();

 

 

3 原型模式,这里就要说到prototype。我们创建的每个函数都有有一个 prototype(原型)属性,它也是一个对象,它的用途是包含有特定类型的所有实例的属性和方法。不推荐使用这种模式。

下面例子,我们把所有方法一个个添加到prototype上,但由于prototype上方法属于一种共享,这些方法有些别人用的到,有些别人根本用不到,有些别人想用的没有的方法还要再次往prototype上添加。这样就不好了,所以最常用的模式其实是混合型的。

//prototype pattern
function Abby(){}

Abby.prototype.name = "Abby";
Abby.prototype.age = "22";
Abby.prototype.sayName = function(){
    alert("prototype pattern: " + this.name);
}

var person1 = new Abby();
person1.sayName();

 

 

4 构造函数模式和原型模式的混合类型。将所有属性不是方法的属性定义在函数中(构造函数方式),将所有属性值为方法的属性利用prototype在函数之外定义(原型方式)。 推荐使用这种方式创建对象。

//hybrid constructor & prototype pattern
function Student(name, sno){
  this.name = name;
  this.sno = sno;
  this.sayName = function(){
    alert("hybrid constructor & prototype pattern: " + this.name);
  }
}

Student.prototype = {
  constructor : Student,
  teacher : ["mike", "abby"],
  sayTeacher : function(){
    alert("hybrid constructor & prototype pattern(teacher): " + this.teacher);
  }
}

var zhangsan = new Student("zhangsan", "22");
var lisi = new Student("lisi", "23");
zhangsan.sayName();
lisi.sayName();
zhangsan.sayTeacher();
lisi.sayTeacher();

 

 

5 动态原型方式

动态原型方式可以理解为混合模式的一个特例。该模式中,属性为方法 的属性直接在函数中进行了定义,但是因为if从句从而保证创建该对象的实例时,属性的方法不会被重复创建。推荐使用这种模式。

//dynamic prototype pattern
function Person(){
  this.name = "Mike";
  this.age = 22;
}
if (typeof Person._lev == "undefined"){
   Person.prototype.lev = function(){
     return this.name;
   }
   Person._lev = true;
}

var x = new Person();
alert(x.lev());

 

 

6. 寄生构造函数模式

//parasitic constructor pattern (hybird factory)
function Person1(name, age, job){
  var o = new Object();
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function(){
    alert(this.name);
  }
  return o;
}

var mike = new Person1("Mike", 22, "Software Engineer");
mike.sayName();

 

 

7 稳妥构造函数模式,这种模式不用this,不用new,目的是安全,这是一种方法,不是主流

//durable constructor pattern
function Person2(name, age, job){
  var o = new Object;
  o.name = name;
  o.age = age;
  o.job = job;
  o.sayName = function(){
    alert(name);
  }
  return o;
}

var mike = Person2("Mike", 22, "Software Engineer");
mike.sayName();

 

 

JS中的继承主要依靠原型链。

 

每个构造函数都拥有一个原型对象,原型对象都包含一个指向构造函数的指针(constructor),实例都包含一个指向原型对象的内部指针(_proto_)。

如果对原型进行多次赋值,那么后面的赋值会覆盖前面的,也就是通过原型链只能继承离实例化最近的一个 原型对象。

原型链继承的本质就是一个单链表的深度搜索。例如,原型对象(Son.prototype)等于另一个原型(Person)的实例(person1),那么此时的原型对象(Son.prototype)将包含一个指向另一个原型(Person.prototype)的指针,相应的,另有一个原型(Person.prototype)中也包含着一个指向另一个构造函数(Person())的指针。

再如,另一个原型(Person.prototype)又是另一个类型(Person)的实例(person1),那么上述关系依旧成立,如此层层递进,就构成了实例与原型的链条。这就是所谓的原型链。

所有引用类型默认继承了Object类型,所有函数的默认原型都是Object的实例,因此默认原型都会包含一个内部指针,指向Object.prototype.这也正是自定义类型能通过使用toString()等默认方法的原因。

在通过原型链实现继承时,不能使用对象字面量创建原型对象,这样会重写原型链。

 

 

call函数的用法(可用于实现继承)

call([thisObj[,arg1[, arg2[,   [,.argN]]]]]),调用一个对象的一个方法,以另一个对象替换当前对象。

call方法可以用来代替另一个对象调用一个方法。call方法可将一个函数的对象上下文从初始的上下文改变为由htisObj指定的新对象。如果没有提供thisObj参数,那么Global对象被用作thisObj。

function Animal(name){
  this.name = name;
  this.showName = function(){
    alert(this.name);
  }
}

function Cat(name){
  Animal.call(this, name);
}

var cat = new Cat("Black Cat");
cat.showName();

Animal.call(this) 的意思就是使用 Animal对象代替this对象,那么 Cat中不就有Animal的所有属性和方法了吗,Cat对象就能够直接调用Animal的方法以及属性了.

同样,如果使用多个call就可以实现多重继承。

 

 

new操作符创建实例的过程:创建一个新对象->将构造函数的作用域赋给新对象(因此this就指向了这个新对象)->执行构造函数的代码(为这个新对象添加属性)->返回新对象

你可能感兴趣的:(JS如何创建对象和继承对象)