浅谈JS对象的创建、原型、原型链继承

JS的内置对象,可分为两类:

  • 数据封装类对象:Object、Boolean、Number、String、Array
  • 其他对象:Function、Date、Error、Math、RegExp、Arguments

自然,除了内置对象外,可以通过JS代码自定义对象。

先总结下创建对象的方式,每种方式继承的原型对象不同:

  • 构造函数:原型为构造函数的prototype属性
  • Object.create():原型为传入的第一个参数,若第一个参数为null,以Object.prototype为原型;第二个参数为可选的属性描述符

下面分别看一下代码示例:

1. 构造函数方式
function Phone(brand) {
  this.brand = brand
}
let nokia = new Phone('Nokia')
console.log(nokia.constructor === Phone); // true
console.log(nokia.constructor.prototype === Phone.prototype); // true
console.log(Phone.prototype.__proto__ === Object.prototype); // true => the final relationship between Phone() and Object()
console.log('Object.prototype.__proto__: ', Object.prototype.__proto__); // null

function Smartphone(model) {
  this.model = model
}
let iphone8 = new Smartphone('iphone8')
console.log(iphone8.constructor === Smartphone); // true

// prototype继承
Smartphone.prototype = new Phone('Huawei')
let honor = new Smartphone('honor')
console.log(honor.constructor === Smartphone); // false
console.log(honor.constructor === Phone); // true
console.log(honor.brand); // Huawei => 继承了brand属性
console.log(honor.model); // honor

// 直接以字面量形式声明时,相当于构造函数为Object
let ironman = {name: 'Tony Stark'}
console.log(ironman.constructor === Object) // true
console.log(ironman.constructor.prototype === Object.prototype) // true
复制代码
2. 利用Object.create()
// 建立一个原型为null的对象
let spiderman = Object.create(null, {
  props: {
    name: 'Peter Park'
  }
});
console.log(spiderman.constructor); // => undefined
    
// 创建一个原型为Array的对象
let array = Object.create(Array.prototype, {});
console.log(array.constructor); // => Array()
console.log(array.constructor.prototype); // => [constructor: ƒ, ...]

// 创建一个原型为自定义类的对象
function Car() {
  this.fix = function() {
    console.log('going to fix');
  }
}
let audi = Object.create(Car.prototype, {});
audi.ov = '3.0T'
Car.prototype.charge = function() {
  console.log('going to charge');
}
console.log(audi.constructor); // Car()
console.log(audi.constructor.prototype); // {charge: ƒ, constructor: ƒ}
复制代码

js通过对原型的操作,可以模拟高级语言对象中的继承特性:

  • prototype是函数层面的属性,隐性原型属性__proto__是对象(包括函数)层面的属性。
  • 一个对象的__proto__,即是其构造器函数的prototype。
  • prototype作为一个对象,亦拥有__proto__属性,指向的是更上一层构造器函数的prototype。
  • 直到__proto__指向的是最上层的Object.prototype,且到此后,Object.prototype.__proto__的值为null。
  • JS的新版本趋势中,逐步开始模拟高级语言(特别是Java)的特性,描述实例成员、静态成员、继承等特性,越来接近面向对象编程。

进一步看下prototype继承:

将某个类的prototype指向为某个对象后,此类将会继承该对象的所有实例成员,静态成员除外。看例子:

function Phone(brand) {
  this.brand = brand
  this.online = function() {
    console.log(brand + ' is going to online');
  }
}
let nokia = new Phone('Nokia')
console.log(nokia.__proto__ === nokia.constructor.prototype); // true => 对象的__proto__即是其构造器的prototype
console.log(nokia.constructor.prototype.__proto__ === Object.prototype); // true
console.log('prototype of nokia: ', nokia.prototype); // undefined => 可再次看出prototype是构造器层面的属性,且__proto__是对象层面的属性
nokia.online(); // Nokia is going to online
Phone.prototype.onMsg = function() {
  console.log('nokia message coming');
}
nokia.onMsg(); // nokia message coming

function Smartphone(model) {
  this.model = model
  this.oncalling = function() {
    console.log(model + ' is on calling');
  }
}
let iphone8 = new Smartphone('iphone8')
iphone8.oncalling(); // iphone8 is on calling

// 继承方式之一:
// 此方式优缺点:简单易于实现, 但若为子类新增属性和方法,要在赋值了prototype之后执行, 无法实现多继承
Smartphone.prototype = new Phone('Xiaomi') // 继承Phone对象实例的所有成员,静态成员除外
let iphoneX = new Smartphone('iphoneX')

console.log(iphoneX.brand); // Xiaomi
console.log(iphoneX.model); // iphoneX
iphoneX.online(); // Xiaomi is going to online
iphoneX.onMsg(); // nokia message coming
iphoneX.oncalling(); // iphoneX is on calling

console.log(iphoneX instanceof Phone); // true 
console.log(iphoneX instanceof Smartphone); // true
复制代码

顺带提一下call方法也可以实现继承:

function Animal(name){   
  this.name = name;   
  this.showName = function(){   
    console.log(this.name);   
  }   
}   
function Cat(name){  
  Animal.call(this, name);  
}    
var cat = new Cat("Black Cat");   
cat.showName(); // Black Cat
复制代码

进一步看下原型链

function Ball(name){
  this.name = name;
  this.showName = function () {
    console.log('I am ' + this.name + ' from this'); 
  }
}
Ball.prototype.showName = function () {
  console.log('I am ' + this.name + ' from prototype'); 
}
let football = new Ball("football");
football.fly = function () {
  console.log(this.name + ' is flying');
}
football.fly(); // football is flying

// 先从自身找,找不到在__proto__中去找,没找到,去找上层__proto__,直到结果为null为止
football.showName(); // I am football from this
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值