浅谈javascript的原型继承

  请看源码:

  

复制代码 代码如下:

  function clone(o) {

  var F = function(){};

  F.prototype = o;

  return new F();

  }

  首先看ext(4.1的1896行开始)的原型式继承。

  

复制代码 代码如下:

  var TemplateClass = function(){};

  var ExtObject = Ext.Object = {

  chain: function (object) {

  TemplateClass.prototype = object;

  var result = new TemplateClass();

  TemplateClass.prototype = null;

  return result;

  }

  }

  这里清除了object的prototype。

  再看一下jquery是怎么玩的继承。

  

复制代码 代码如下:

  var jQuery = function( selector, context ) {

  return new jQuery.fn.init( selector, context, rootjQuery );

  };

  -----------------------

  jQuery.fn = jQuery.prototype = {

  constructor: jQuery,

  init: function( selector, context, rootjQuery ) {

  -----------------------

  }

  }

  -------------------

  jQuery.fn.init.prototype = jQuery.fn;

  jquery玩的就比较高,借助jQuery.fn.init来完成,但是思路一样。

  司徒正美的mass里也有类似的继承,在lang_fix.js里面第17行:

  

复制代码 代码如下:

  create: function(o){

  if (arguments.length > 1) {

  $.log(" Object.create implementation only accepts the first parameter.")

  }

  function F() {}

  F.prototype = o;

  return new F();

  }

  查看了一下es5的官方,找到了他的兼容补丁:

  

复制代码 代码如下:

  // ES5 15.2.3.5

  // http://es5.github.com/#x15.2.3.5

  if (!Object.create) {

  Object.create = function create(prototype, properties) {

  var object;

  if (prototype === null) {

  object = { "__proto__": null };

  } else {

  if (typeof prototype != "object") {

  throw new TypeError("typeof prototype["+(typeof prototype)+"] != 'object'");

  }

  var Type = function () {};

  Type.prototype = prototype;

  object = new Type();

  // IE has no built-in implementation of `Object.getPrototypeOf`

  // neither `__proto__`, but this manually setting `__proto__` will

  // guarantee that `Object.getPrototypeOf` will work as expected with

  // objects created using `Object.create`

  object.__proto__ = prototype;

  }

  if (properties !== void 0) {

  Object.defineProperties(object, properties);

  }

  return object;

  };

  }

  上面的代码考虑的就比较全面,但是需要另外引入Object.defineProperties的补丁才行,源码相对就比较多了。

  

复制代码 代码如下:

  // ES5 15.2.3.6

  // http://es5.github.com/#x15.2.3.6

  // Patch for WebKit and IE8 standard mode

  // Designed by hax <hax.github.com>

  // related issue: https://github.com/kriskowal/es5-shim/issues#issue/5

  // IE8 Reference:

  // http://msdn.microsoft.com/en-us/library/dd282900.aspx

  // http://msdn.microsoft.com/en-us/library/dd229916.aspx

  // WebKit Bugs:

  // https://bugs.webkit.org/show_bug.cgi?id=36423

  function doesDefinePropertyWork(object) {

  try {

  Object.defineProperty(object, "sentinel", {});

  return "sentinel" in object;

  } catch (exception) {

  // returns falsy

  }

  }

  // check whether defineProperty works if it's given. Otherwise,

  // shim partially.

  if (Object.defineProperty) {

  var definePropertyWorksOnObject = doesDefinePropertyWork({});

  var definePropertyWorksOnDom = typeof document == "undefined" ||

  doesDefinePropertyWork(document.createElement("div"));

  if (!definePropertyWorksOnObject || !definePropertyWorksOnDom) {

  var definePropertyFallback = Object.defineProperty;

  }

  }

  if (!Object.defineProperty || definePropertyFallback) {

  var ERR_NON_OBJECT_DESCRIPTOR = "Property description must be an object: ";

  var ERR_NON_OBJECT_TARGET = "Object.defineProperty called on non-object: "

  var ERR_ACCESSORS_NOT_SUPPORTED = "getters & setters can not be defined " +

  "on this javascript engine";

  Object.defineProperty = function defineProperty(object, property, descriptor) {

  if ((typeof object != "object" && typeof object != "function") || object === null) {

  throw new TypeError(ERR_NON_OBJECT_TARGET + object);

  }

  if ((typeof descriptor != "object" && typeof descriptor != "function") || descriptor === null) {

  throw new TypeError(ERR_NON_OBJECT_DESCRIPTOR + descriptor);

  }

  // make a valiant attempt to use the real defineProperty

  // for I8's DOM elements.

  if (definePropertyFallback) {

  try {

  return definePropertyFallback.call(Object, object, property, descriptor);

  } catch (exception) {

  // try the shim if the real one doesn't work

  }

  }

  // If it's a data property.

  if (owns(descriptor, "value")) {

  // fail silently if "writable", "enumerable", or "configurable"

  // are requested but not supported

  /*

  // alternate approach:

  if ( // can't implement these features; allow false but not true

  !(owns(descriptor, "writable") ? descriptor.writable : true) ||

  !(owns(descriptor, "enumerable") ? descriptor.enumerable : true) ||

  !(owns(descriptor, "configurable") ? descriptor.configurable : true)

  )

  throw new RangeError(

  "This implementation of Object.defineProperty does not " +

  "support configurable, enumerable, or writable."

  );

  */

  if (supportsAccessors && (lookupGetter(object, property) ||

  lookupSetter(object, property)))

  {

  // As accessors are supported only on engines implementing

  // `__proto__` we can safely override `__proto__` while defining

  // a property to make sure that we don't hit an inherited

  // accessor.

  var prototype = object.__proto__;

  object.__proto__ = prototypeOfObject;

  // Deleting a property anyway since getter / setter may be

  // defined on object itself.

  delete object[property];

  object[property] = descriptor.value;

  // Setting original `__proto__` back now.

  object.__proto__ = prototype;

  } else {

  object[property] = descriptor.value;

  }

  } else {

  if (!supportsAccessors) {

  throw new TypeError(ERR_ACCESSORS_NOT_SUPPORTED);

  }

  // If we got that far then getters and setters can be defined !!

  if (owns(descriptor, "get")) {

  defineGetter(object, property, descriptor.get);

  }

  if (owns(descriptor, "set")) {

  defineSetter(object, property, descriptor.set);

  }

  }

  return object;

  };

  }

  // ES5 15.2.3.7

  // http://es5.github.com/#x15.2.3.7

  if (!Object.defineProperties) {

  Object.defineProperties = function defineProperties(object, properties) {

  for (var property in properties) {

  if (owns(properties, property) && property != "__proto__") {

  Object.defineProperty(object, property, properties[property]);

  }

  }

  return object;

  };

  }

  EcmaScript6的类继承。

  

复制代码 代码如下:

  class module extends Base {

  constructor() {

  }

  }

  越玩越像java了,不过es6很多浏览器还不支持。

  最后推荐的写法:

  

复制代码 代码如下:

  if (!Object.create) {

  Object.create = function create(o) {

  var F = function(){};

  F.prototype = o;

  var result = new F();

  F.prototype = null;

  return result;

  }

  }