JavaScript 原型与继承机制详解(4)

  要注意的一点是,原型链的遍历只会发生在 [[getter]] 操作上,也就是取值操作,也可以称之右查找(RHS)。相反,若是进行 [[setter]] 操作,也就是赋值操作,也可以称作左查找(LHS),则不会遍历原型链,这条原则保证了我们在对对象进行操作的时候不会影响到原型链:

1 var obj1 = {
2    x:1
3 }
4
5 var obj2 = {
6     __proto__:obj1
7 }
8
9 console.log(obj2.x);  //1
10
11 obj2.x = 2;
12
13 console.log(obj2.x);  //2
14 console.log(obj1.x);  //1(并没有发生变化)

  在遍历原型链中,如果访问带有 this 引用的方法,可能会发生令你意想不到的结果:

1 var obj1 = { 2 x:1, 3 foo: function () { 4 console.log(this.x); 5 } 6 } 7 8 var obj2 = { 9 x:2, 10 __proto__:obj1 11 } 12 13 obj2.foo(); //2

  在上面的内容中,我们讨论过,对象的原型相当于父类,我们可以继承它所拥有的属性和方法,所以在我们访问 foo() 函数的时候时候,实际上调用该方法的对象是 obj2 而不是 obj1。关于更详细的内容,需要了解 this 和上下文绑定,这不在本篇文章的讨论范围之内。

  关于原型链的问题,大家需要理解的一点是,任何对象的原型链终点,都是 Object.prototype,可以把 Object 理解为所有对象的父类,类似于 JAVA 一样,所以说所有对象都可以调用一些 Object.prototype 上面的方法,比如 Object.prototype.valueOf() 以及 Object.prototype.toString() 等等。所有的 string 类型,其原型为 String.prototype ,String.prototype 是一个对象,所以其原型也就是 Object.prototype。这就是我们为什么能够在一个 string 类型的值上调用一些方法,比如 String.prototype.concat() 等等。同理所有数组类型的值其原型是 Array.prototype,数字类型的值其原型是 Number.prototype:

1 console.log({}.__proto__ === Object.prototype);  //true
2
3 console.log("hello".__proto__ === String.prototype);  //true
4
5 console.log(1..__proto__ === Number.prototype);  //true
6 //注意用字面量访问数字类型方法时,第一个点默认是小数标志
7
8 console.log([].__proto__ === Array.prototype);  //true

  理解了原型链的遍历操作,我们现在就可以学习如何添加属于自己的方法。我们现在知道了所有字符串的原型都是 String.prototype ,那么我们可以对其进行修改来设置我们自己的内置方法:

1 String.prototype.foo = function () { 2 return this + " foo"; 3 } 4 5 console.log("bar".foo()); //bar foo

  所以说,在处理一些浏览器兼容性问题的时候,我们可以直接修改内置对象来兼容一些旧浏览器不支持的方法,比如 String.prototype.trim() :

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/9fffa9f22ed89d78b1b09dc5ec45d6c5.html