原型链


原型对象

任何函数都可以成为构造函数,但并不能将任何函数都叫做构造函数,函数只有通过new关键字被实例化时才能成为构造函数。如下:

var Test = function(){}
Test.prototype.aa = '11';  // 为原型对象新的属性

var test1 = new Test();
console.log(test1.aa);  // "11"

var test2 = new Test();
test2.name = '22'      // 原型对象上的属性只能访问,不能修改;因此此处是为p1创建新的属性name,并赋值; 
console.log(test1.aa);  // "22"

js中每个函数都有一个prototype属性(原型对象),该属性是函数独有的;在prototype对象中的属性或方法,会被该函数实例化的所有对象共享

js中每个对象都有两个属性constructor和__proto__,constructor指向实例化该对象的构造方法,__proto__指向实例化该对象的构造方法中的prototype属性(原型对象);

此例中,test1和test2这两个对象都是通过构造方法Test实例化的,因此它们的构造方法都是Test,它们的__proto__属性也都指向Test.prototype原型对象;

根据js原型链继承规则,当test1或test2在访问属性或方法时,会先从自身查找是否对应的属性或方法;若没有,就会向上查找__proto__属性所指向的原型对象中是否有属性或方法;若还是没有,则会继续向上查找原型对象的__proto__属性所指向的原型对象是否有属性或方法,以此类推,直到最顶层的Object对象;Object的__proto__为null,即Object没有原型对象。


注:实例对象可以共享访问原型对象的属性,但不能修改;修改时会为实例对象创建一个新的属性。


Function对象

在js中万物皆对象,包括js中的函数实际也都是一个Function对象,所有函数(包括构造函数)都是由Function对象的构造函数Function()实例化的;运行如下代码便可验证这个结论。

(function(){}).constructor === Function // true
// 或
Test instanceof Function // true

即,函数对象Function与Array、Map一样,都是一种对象类型;Function的原型对象最终也是会追溯到Object。

详见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Function


Object对象

在JavaScript中,几乎所有对象都是Object类型的实例,所有对象都从Object.prototype继承方法和属性;

test instanceof Object // true

Function、Array、Map等这些对象不仅可以使用自身的属性、方法,还都能使用Object原型对象中的属性和方法。

详见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object


注意事项

除非有特殊需求,否则不建议去扩展原生对象和原型;原因有如下几点:

1>. 原型链属性污染:原型属性是所有对象共享的,所以一处修改会影响其它所有对象,例如:obj.__proto__['sex'] = '1'

2>. 使用混乱:原型方法很容易与原生方法混在一起无法区分;在实际开发应尽量减少全局函数或变量,以避免冲突;

3>. 如果自定义的原型函数错误的覆盖了原生函数,将对所有使用到的地方造成致命伤害;尤其是我们并不知道JS未来会扩展哪些原生函数,因此也不清楚未来会不会与自定义的函数重复;



原型对象MDN文档:https://developer.mozilla.org/zh-CN/docs/Learn/JavaScript/Objects/Object_prototypes



举报

© 著作权归作者所有


0