javascript原型原型链 学习随笔

时间:2019-07-04
本文章向大家介绍javascript原型原型链 学习随笔,主要包括javascript原型原型链 学习随笔使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

理解原型和原型链。需从构造函数、__proto__属性(IE11以下这个属性是undefined,请使用chrome调试)、prototype属性入手。

JS内置的好多函数,这些函数又被叫做构造函数。如:Object---Array---Function---Math---Date---String---Number---Boolean---Symbol---RegExp。

JS里,所有的对象,都是其构造函数的实例。如{}是Object的一个实例,[]是Array的一个实例。fn() {}是Function的一个实例...

一般情况,我们用对象字面量的方式创建Object的实例。

如:const obj = {}; 这种创建方式是完全等于const obj = new Object();  当然字面量方式是推荐写法。

只要是函数,甭管构造不构造,都有一个prototype属性(指针,其指向函数的原型对象);该属性的值是一个对象,我们管它叫原型对象,其实它就是一个普通对象。对象该有的他都有。它还有个特殊的属性--constructor。属性值就是前面的函数。

关系图:

 

当调用构造函数创建实例时,实例内部将包含一个属性,在chrome、ff。这个属性是__proto__。这个属性的值是其构造函数的原型对象。

 

如上所示,obj是Object构造函数的一个实例,实例上有__proto__属性。这个属性全等于Object构造函数的原型对象。

 

多亏有这个__proto__指针,我们在某构造函数的原型对象上定义的属性和方法都能被其所有的实例所共享。

在一些浏览器里(没错,就是IE),这个指针是不可见的。我们可以用 isPrototypeof()方法或者Object.getPrototypeOf()方法来判断实例与原型之间是否存在这种关系。

 

IE9以下就不支持Object.getPrototypeOf()方法了。

如果实例的 __proto__属性 或者叫 指向构造函数原型对象的指针 指向调用isPrototypeOf()方法的对象(Fn.prototype)。那么这个方法返回值是true。

这里一定要理解,实例的__proto__属性或者叫指向构造函数原型对象的指针是实实在在存在的,只不过有些浏览器给他取了个名字__proto__。有些浏览器没有去定义这个指针的名字。

Object.getPrototypeOf(fn1)方法返回的对象是fn1的构造函数的原型对象。

接下来就是原型链了

在js里。Object类型是基础类型,其他所有的引用类型都继承这个类型。

那么要怎么实现继承呢。

JS实现继承的方式主要就是通过原型链方法。

前面学习时,我们已经得知每个构造函数都有一个原型对象,构造函数的实例有一个指向原型对象的指针。

我们要做的就是。

把另外一个构造函数的实例赋值给原型对象。

首先,我们再定义一个函数Foo,此时Foo.prototype.__proto__ 全等于 Object.prototype;

(原型对象也是对象,自然也会有__proto__指针,如果没有去改它。默认就是指向Object.prototype呦)

接着。把另外一个构造函数的实例赋值给Foo.prototype。

显而易见,根据引用类型值的特性,Foo.prototype 和 fn1指向同一个对象。

这个对象的__proto__属性又指向其构造函数的原型对象。由此Foo函数的原型对象就包含了指向Fn的原型对象的指针。

即:Foo.prototype.__proto__ === Fn.prototype。

如果Fn的原型对象也是另外另外一个函数的实例。。。上述关系仍然成立,如此层层递进。一直指到Object.prototype。

这个对象就比较特殊了。它就没有__proto__属性。Object.prototype.__proto__ === null。原型链到此结束。

上图:

以上定义了两个函数。Person是超类型,Teacher子类型。人可以不是老师,但是老师一定是人嘛。哈哈哈。

属性的继承是通过

构造函数的this指向他的实例。通过call方法。把Person函数的this绑定到Teacher的实例xm,xh上。相当于xm.name = '小明';xh.name = ’小花‘;

方法的继承通过

这步实现了原型链关系。通过向原型链查找,只要存在于原型链上的方法,实例都能用。

确定原型和实例的关系

除了上面的isPrototypeOf()方法外,还有一个方法广为人知。就是使用Instance of 。

用这个操作符测试实例和原型链中出现过的构造函数。结果会返回true。

 

实现一个简单的instanceof操作符。

1.

1 Object.prototype.myInstanceOf = function (Func) {
2   if (typeof Func !== 'function') {
3     return false;
4   }
5   return Func.prototype.isPrototypeOf(this);
6 };

2.

 1 Object.prototype.myInstanceOf = function (Func) {
 2   if (typeof Func !== 'function') return false;
 3   
 4   function _fn(instance, Func) {
 5     if (instance.__proto__) {
 6       if (instance.__proto__ !== Func.prototype) {
 7         return _fn(instance.__proto__, Func);
 8       } else {
 9         return true;
10       }
11     }
12     return false;
13   }
14   return _fn(this, Func);
15 };

3.

Object.prototype.myInstanceOf = function (Func) {
  if (typeof Func !== 'function') {
    return false;
  }
  let _obj = Object.getPrototypeOf(this),
      res = false;
  while (_obj) {
    if (_obj === Func.prototype) {
      res = true;
      break;
    }
    _obj = Object.getPrototypeOf(_obj);
  }
  return res;
};

结果:

也不知道有没有什么边界情况下的错误。。。

累死了。。

 

$flag 上一页 下一页