深入理解原型对象、原型链(二)

217 阅读2分钟

前言

我们从上一章深入理解原型对象、原型链(一)知道:foo.__proto__ === Foo.prototype

function Foo(name){
    this.name=name
}

//在原型对象上定义方法
Foo.prototype.say = function(){
    console.log(123)
} 
var foo = new Foo('张三')
var foo2 = new Foo('李四')
foo.say(); // 123
foo2.say(); // 123
foo.__proto__.say2 =  function(){console.log(456)}  //在原型对象上定义方法
foo.say2(); // 456
foo2.say2(); // 456

我们发现由于 Foo.prototype === foo.__proto__都是原型对象,在原型对象上定义方法,实例对象都能访问。

function Bar(age){this.age=age}
function Zing(sex,height){this.sex=sex;this.height = height}
var foo3 = new Foo('王五')
var bar = new Bar(18)
var zing = new Zing('男',80)
bar.__proto__ = zing;
foo3.__proto__ = bar;
foo3.sex // 男

我们打印下foo3

image.png

发现:

  1. foo有自身的属性name和指向Bar的[[Prototype]] // chrome浏览器显示的是Zing,但通过foo3.__proto === bar得知,属性指向应该是Bar,应该是chrome浏览器显示bug。
  2. foo3.__proto__Bar有自身的属性age和指向Zing的[[Prototype]]
  3. foo3.__proto__.__proto__Zing有自身的属性sex和height和指向Object构造器是Zing的[[Prototype]]
  4. foo3.__proto__.__proto__.__proto__指向Zing.prototype
  5. foo3.__proto__.__proto__.__proto__指向Object.prototype
  6. foo3.__proto__.__proto__.__proto__.__proto__指向null
foo3.age = '9'
bar.sex = '女'
foo3.hello() //由于原型链上没找到该属性,报错

发现:如果在上一层的原型对象中发现了属性就无法再访问下一层属性。

小节:

对象在访问属性时,先访问自身属性,如果有直接返回,没有就访问下一级原型对象的属性,直到访问到Object.prototype,如果还没有,直接会报错,这样就能解释了为啥对象都会有hasOwnProperty这些方法,就是因为这些方法都是定义在Object上,而对象又都是Object的子类.

应用

定义实例属性、方法

function Person(name){this.name = name}
Person.prototype.sayHello = function(){
    console.log('hello' + this.name)
}

委托

// 基础值
var obj = {
    sayHello() {
        console.log('hello')
    },
    saySorry(){
        console.log('sorry')
    }
}

var o = {};
var u = {};
Object.setPrototypeOf(o,obj); //等同于 o.__proto__ = obj;
o.sayHello(); // hello
o.saySorry(); // sorry

// 同理
Object.setPrototypeOf(u,obj); 
u.sayHello(); // hello
u.saySorry(); // sorry

// 这样 我们可以将obj这个对象里的方法抽象出来作为公共方法,如果其他对象用到该方法,可以直接委托.