JavaScript 基础系列之对象原型

什么是对象原型

JavaScript 中所有的对象都有一个内置属性,称为它的 prototype(原型)。它本身是一个对象,故原型对象也会有它自己的原型,逐渐构成了原型链。原型链终止于拥有 null 作为其原型的对象上。

准确地说,这些属性和方法定义在Object的构造器函数(constructor functions)之上的prototype属性上,而非对象实例本身。

因此可以看出它的优点: 所有对象实例可以共享它包含的属性和方法

看下面例子

function Person() {}
console.log(Person.prototype) // {constructor: ƒ}
Person.prototype.name = '张三'
Person.prototype.age = 18
Person.prototype.getName = function () {
    console.log('name:' + this.name)
}
var p1 = new Person()
p1.getName() // name:张三
var p2 = new Person()
p2.getName() // name:张三

console.log(p1.getName == p2.getName) // true
console.log(p1.name === p2.name) // true
console.log(Person.prototype.constructor) // ƒ Person() {}
console.log(Person.prototype.constructor.prototype) // {name: "张三", age: 18, getName: ƒ, constructor: ƒ}
console.log(p1.prototype) // undefind
console.log(p1.constructor) // ƒ Person() {}
console.log(p1) // Person {}

JavaScript 基础系列之对象原型
由上可得:

Person 有个默认的属性prototype函数可以有属性。每个函数都有一个特殊的属性叫作原型(prototype)

p1和p2访问的都是同一个getName()函数,即他们的属性和方法都是共享的

默认情况下所有的函数都有一个constructor(构造函数)属性。该属性指向了prototype属性所在函数。如:Person.prototype.constructor 指向的是 Person。

打印 p1:

JavaScript 基础系列之对象原型

p1有个__proto__ 属性,该属性内还有:Person的实例、constructor、__proto__。以此提供了一个原型链。

JavaScript 基础系列之对象原型

prototype 属性:继承成员被定义的地方

prototype 属性的值是一个对象,我们希望被原型链下游的对象继承的属性和方法,都被储存在其中。

Object.prototype.watch()、``Object.prototype.valueOf() 等等成员,适用于任何继承自 Object() 的对象类型,包括使用构造器创建的新的对象实例。

Object.is()Object.keys(),以及其他不在 prototype 对象内的成员,不会被“对象实例”或“继承自 Object() 的对象类型”所继承。这些方法/属性仅能被 Object() 构造器自身使用

console.log(Person.prototype) // {name: "张三", age: 18, getName: ƒ, constructor: ƒ}
console.log(Object.prototype) //{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}

prototype 属性包含(指向)一个对象,你在这个对象中定义需要被继承的属性和方法。

create()

create() 实际做的是从指定原型对象创建一个新的对象。

 function Person(name, age) {
    this.name = name
    this.age = age 
    this.getName = function () {
      console.log('name:' + this.name)
    }
  }
  var p1 = new Person('张三', 18)

  var p3 = Object.create(p1)
  console.log(p3) 
constructor

每个实例对象都从原型中继承了一个constructor属性,该属性指向了用于构造此实例对象的构造函数

// 获得对象实例的构造器的名字
console.log(p1.constructor.name) // Person

修改原型

Person构造器的 prototype 属性添加一个新的方法。

function Person(name, age, sex) {
    this.name = name
    this.age = age
    this.sex = sex
    this.getName = function () {
      console.log('name:' + this.name)
    }
}
var p1 = new Person('张三', 18, '男')

Person.prototype.getSex = function() {
    console.log('sex:' + this.sex);
}
p1.getSex() // sex:男

getSex 方法虽在 p1 实例后定义,但p1也可使用。旧有对象实例的可用功能被自动更新了
这种继承模型下,上游对象的方法不会复制到下游的对象实例中;下游对象本身虽然没有定义这些方法,但浏览器会通过上溯原型链、从上游对象中找到它们。这种继承模型提供了一个强大而可扩展的功能系统。

一种极其常见的对象定义模式是,在构造器(函数体)中定义属性、在 prototype 属性上定义方法。如此,构造器只包含属性定义,而方法则分装在不同的代码块,代码更具可读性。

// 构造器及其属性定义
function Test(a,b,c,d) {
  // 属性定义
};

// 定义第一个方法
Test.prototype.x = function () { ... }

// 定义第二个方法
Test.prototype.y = function () { ... }

继承

例子

function Person(name, age, sex) {
    this.name = name
    this.age = age
    this.sex = sex
    this.getName = function () {
      console.log('name:' + this.name)
    }
}
构造函数继承
var p1 = new Person('张三'18, 'nan')
p1.getName()
原型式继承

继承的对象函数并不是通过复制而来,而是通过原型链继承(通常被称为 原型式继承 —— prototypal inheritance)

function Person(name, age, sex) {
    this.name = name
    this.age = age
    this.sex = sex
    this.getName = function () {
      console.log('name:' + this.name)
    }
}

Person.prototype.getSex = function() {
    console.log('sex:' + this.sex);
}

如果一个新的函数要继承上来构造函数的属性和方法,还有增加新的属性和方法:

function Teacher(name, age, sex, profession) {
  Person.call(this, name, age, sex);

  this.profession = profession;
}
var t1 = new Teacher('王二', 30, '男', '老师')
console.log(t1) // Teacher {name: "王二", age: 30, sex: "男", profession: "老师", getName: ƒ}

参考文章:blog.csdn.net/flyingpig20…

原文链接:https://juejin.cn/post/7327263242082205707 作者:炳子

(0)
上一篇 2024年1月24日 下午4:05
下一篇 2024年1月24日 下午4:16

相关推荐

发表回复

登录后才能评论