Javascript 对象创建多种方式 原型链

一、对象创建

1、new Object 方式

  直接赋上属性和方法

var obj = new Object(); 
obj.name = '娃娃';
obj.showName = function(){ 
  alert(obj.name);
}
//调用 obj.showName();

  缺点:每次使用都要写同样的代码,不能重用

2、工厂方法方式

  把同样的代码封装在一个函数方法里,是对1、改进,减少重复代码。 

function CreatePerson(name){ 
   var obj = new Object();   //原料
   obj.name = name;         //加工
   obj.showName = function(){
     alert(this.name);
 } 
   return obj;//出厂
}
var p1 = CreatePerson('哇哇');
p1.showName();
var p2 = CreatePerson('哈哈');
p2.showName();
//其实就是简单的封装函数,整个过程像工厂的流水线,所以叫工厂方式

  缺点:无法识别创建的对象的类型。因为全部都是Object,没有区分度,不像Date、Array等,因此出现了构造函数模式。

3、构造函数方式

  函数名首字母大写,这是为了和普通函数区分,而且有this指针。

function CreatePerson(name){ 
   this.name = name; 
   this.showName = function(){ 
     alert(this.name);
   } 
} 
var p1 = new CreatePerson('娃娃'); 
p1.showName();
var p2 = new CreatePerson('哈哈'); 
p2.showName();

  构造函数本身也是普通函数,取决于使用的方式,可以new(当作构造函数),也可以直接调用(当作普通函数),两者区别是this指针指向不一样。

new CreatePerson('haha'); //CreatePerson
CreatePerson('haha');  //window

  new 内部操作

function CreatePerson(name){ 
   var obj = {}; //声明一个空对象obj 
   obj._proto_= CreatePerson.prototype;
   //把这个对象的_proto_属性指向构造函数的原型对象,这样obj就可以调用CreatePerson原型对象下的所有方法 。
    CreatePerson.apply(obj);   //用apply方法让this指向obj对象
    this.name = name;   //obj对象添加属性,方法
    this.showName = function(){ 
       alert(this.name);
      }; 
    return obj;//返回这个对象
}

  缺点:可见这两个对象并不是共用一个方法,每new一次,系统都会新创建一个内存,这两个对象各自有各自的地盘,但他们具有相同的功能,还不共用。

alert(p1.showName==p2.showName);//false

4、原型+构造函数方式 最优方式

  原型:

    每个函数都有一个prototype属性,它是一个对象,也称作原型对象,我们可以把方法和属性写在它上面(不过原型对象不仅仅有我们写的属性和方法,还有别的),设计时概念。

    而通过这个函数创建出来的实例对象,都能共享这个原型对象下的方法和属性。

  编写方法:

  把共享的属性和方法定义在函数的prototype下,不共享的内容通过构造函数来创建。

function CreatePerson(name){ 
  //定义不共享内容
  this.name = name;
}
//定义共享内容
CreatePerson.prototype.showName = function(){ 
   alert(this.name);
}
var p1 =new CreatePerson('娃娃');
p1.showName();
var p2 = new CreatePerson('哈哈');
p2.showName();
alert(p1.showName==p2.showName);//true

  由此也可以看出,showName()方法是共享的,也就是说他们共用一个内存,更进一步的说它们存在引用关系,也就是说你更改了p1的showName也会影响p2的showName。

  _proto_属性:

  运行时属性,每个实例化对象都有_proto_属性,它是一个指针,指向函数的prototype(设计时属性),保存了函数的prototype的地址,通过该_proto_属性可以让同一构造函数的多个实例对象能共享这个构造函数的prototype(设计时定义)下的方法和属性。

  js中任何对象的值都是保存在堆内存中,我们声明的变量只是一个指针,保存了这个对象的实际地址,所以有了地址就能找到对象。

  所以,_proto_属性实际就是实例化对象和原型对象之间的连接。

二、原型链

  每个函数都可以成为构造函数,每个函数都有原型对象,每个原型对象也可以是一个实例化对象。

  创建了构造函数Function的实例化对象fun,而Function的原型对象(Function.prototype),又是Object的实例对象,根据前边介绍,fun有个_proto_属性,指向了Function.prototype,而Function.prototype(是Object的实例对象)又指向了Object.prototype。

  所以,通过_proto_属性,就形成了一条原型链。每个实例化对象都可以访问到链子上方的方法和属性,所以fun是可以访问Object原型对象下的方法和属性的。实际上所有对象都可以访问到Object的原型对象。

   访问规则先在自身的下面寻找,再去一级一级的往原型链上找
  
function Aaa(){}
Aaa.prototype.num = 3;
var a1 = new Aaa();
a1.num =10;
alert(a1.num); //10

原文地址:https://www.cnblogs.com/shawnhu/p/8470560.html