设计模式之原型,学习笔记

  在常见的编程语言中如果你需要一个对象,那么可以通过类来创建,但是Javascript它并没有类这个概念,javascript创建对象是通过克隆另外一个对象而来的,既然如此那么它肯定有一个基类,这个基类就是Object.prototype,这是一个顶级根对象,其他所有对象都是通过克隆它而来的,比如你通过new Object()实际上就是克隆了Object.prototype。通过克隆我们可以得到一个一模一样的对象,但是这个prototype原型只有函数才有,因此我们得先创建一个函数,如下:

function Fn(){
  this.name = 'JS';
}
Fn.prototype.sayHello = function(){
  alert(this.name);
};

var js = new Fn();
console.log(js);

  这里我们用到了new ,实际上new干了两件事一个是把Fn里面的this指向了js另外一件事就是js的__proto__指向了Fn.prototype,__proto__属于隐藏的属性,但是谷歌浏览器和火狐浏览器控制台已经公开了。__proto__的作用就是,当你这个对象没有某些方法或者属性的时候,这个对象就会通过__proto__上面找,__proto__又指向了那个构造函数的prototype,因此它又跑去prototype上面找对应的属性或方法。

下面我们手动模拟一下new的实现


function createObj(fn){
  var obj = new Object();
  fn.call(obj); //通过call让fn里面的this指向obj
  obj.__proto__ = fn.prototype; //指向fn.prototype 继承方法和属性
  return obj;
}
console.log(createObj(Fn));


  new的内部实现可能要比这复杂,但大致是这样的一个过程。

  ES5提供了一种新的克隆对象方法它叫Object.create(对象);

var obj = {a:1,b:2};
var cloneObj = Object.create(obj);
console.log(cloneObj);


  如果你通过谷歌浏览器你可以看到这样一个画面。


Object {}
  __proto__: Object
    a: 1
    b: 2
    __proto__: Object

  也就是说这个Object.create这个方法实际上就是将cloneObj的__proto__指向了obj。Ok我们也来实现一个。

var obj = {a:1,b:2};

function createObj(obj){
  function Fn(){
  }
  Fn.prototype = obj;
  return new Fn();
}
console.log(createObj(obj));


  有可能你会奇怪,正如我之前郁闷一件事,就是为什么不直接return返回这个obj不就好了吗。


var obj = {a:1,b:2};

function createObj(obj){
  return obj;
}
console.log(createObj(obj));


  虽然你看上去没啥区别,但其实不是这样,实际上通过prototype并不是去真正的创建一个对象,而是继承,这很重要,如果你按照上面的那种错误做法是真的去创建了另一个对象了,这样的话内存中又多出来一个对象,而往往我们没有必要这样做,只是希望如果本身这个对象没有的话,我在去继承你那个对象,这样不岂妙哉。

  通过Object.create来创建对象多少和new Object()还是有区别的,首先Object.create支持传递一个null,如果传的是null的话,它创建的真的是一个彻彻底底的空对象,它的__proto__不指向任何东西,因此它不继承任何的属性和方法,而new Object()创建的它的__proto__指向Object.prototype,简单来说Object.create(null)没有原型,即一个空对象,而new Object()有原型对象。

原文地址:https://www.cnblogs.com/pssp/p/5786238.html