javascript 原型 原型链 继承

__proto__,prototype,constructor

在 JavaScript 中,每当定义一个对象(函数也是对象)时候,对象中都会包含一些预定义的属性。

  1. __proto__属性,所有对象都拥有__proto__属性,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型

  2. prototype属性,只有函数对象才有prototype属性(几乎所有的函数都有)。这个属性是指向自己的原型对象,原型对象的用途就是包含所有实例共享的属性和方法

  3. constructor属性,原型对象的属性,这个属性指回原构造函数。


image


__proto__ 与 prototype

显式原型的作用:用来实现基于原型的继承与属性的共享。
隐式原型的作用:构成原型链,同样用于实现基于原型的继承。


function Person(name, age) {
    var gender = girl // ①
    this.name = name // ②
    this.age = age
}

// ③
Person.prototype.sayName = function() { 
    alert(this.name) 
}

// ④
var kitty = new Person('kitty', 14)

kitty.sayName() // kitty

Person 是一个"构造函数"(它用来"构造"对象,并且是一个函数)

①处gender是该构造函数的“私有属性”

②处的语句定义了该构造函数的“自有属性”

③处的prototype是Person的"原型对象",该对象上定义的所有属性和方法都会被"实例对象"所"继承"

④处的变量"kitty"的值是构造函数Person的“实例对象”,它可以访问到两种属性,一种是通过构造函数生成的“自有属性”,一种是原型对象可以访问的所有属性

原型链

当JavaScript引擎发现一个对象访问一个属性时,会首先查找对象的“自有属性”,如果没有找到则会在__proto__属性指向的原型中继续查找,如果没找到就继续查找,直到找到最顶部的Object.prototype,如果还是没有找到,会返回一个undefined值。这个不断查找的过程,有一个形象生动的名字“攀爬原型链”。

继承

在JavaScript中,实现继承的方式有以下两种:

  1. 创建一个对象并指定其继承对象(原型对象);
  2. 修改构造函数的原型属性(对象);

(一)关于Object.create() 和对象继承

正如之前所说,Object.create()函数是JavaScript提供给我们的一个在创建对象时设置对象内部__proto__属性的API。

var x = { 
    name: 'tom',
    sayName: function() {
        console.log(this.name)
    }
}
var y = Object.create(x, {
    name: {
        configurable: true,
        enumerable: true,
        value: 'kitty',
        writable: true,
    }
})
y.sayName() // 'kitty'

Object.create()函数接收两个参数,第一个参数是创建对象想要继承的原型对象,第二个参数是一个属性描述对象

  1. 创建了一个空对象,并赋值给相应变量;
  2. 将第一个参数对象设置为该对象__proto__属性的值;
  3. 在该对象上调用defineProperty()方法,并将第二个参数传入该方法中;

这样的方法有很多局限,比如我们只能在创建对象时设置对象的继承对象,又比如这种设置继承的方式是一次性的,我们永远无法依靠这种方式创造出多个有相同继承关系的对象,而对于这种情况,我们需要介绍 prototype原型对象。

(二)关于prototype 和构造函数继承

构造函数生产实例对象的过程本身就是一种天然的继承。

实例对象天然的继承着原型对象的所有属性,这其实是JavaScript提供给开发者第二种(也是默认的)设置对象__proto__属性的方法。

function Foo(x, y) {
    this.x = x
    this.y = y
}
Foo.prototype.sayX = function() {
    console.log(this.x)
} 
Foo.prototype.sayY = function() {
    console.log(this.y)
}

function Bar(z) {
    this.z = z 
    this.x = 10
}
Bar.prototype = Object.create(Foo.prototype) // 注意这里
Bar.prototype.sayZ = function() {
    console.log(this.z)
}
Bar.prototype.constructor = Bar

var o = new Bar(1)
o.sayX() // 10
o.sayZ() // 1
(三)构造函数窃取
function Foo(x, y) {
    this.x = x
    this.y = y
}
Foo.prototype.sayX = function() {
    console.log(this.x)
} 
Foo.prototype.sayY = function() {
    console.log(this.y)
}

function Bar(z) {
    this.z = z 
    this.x = 10
    Foo.call(this, z, z) // 注意这里
}
Bar.prototype = Object.create(Foo.prototype) 
Bar.prototype.sayZ = function() {
    console.log(this.z)
}
Bar.prototype.constructor = Bar

var o = new Bar(1)
o.sayX() // 1
o.sayY() // 1
o.sayZ() // 1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值