JavaScript原型(下)

本文深入探讨了JavaScript中Object.create()方法的使用,包括如何创建无原型的对象,以及如何通过它实现对象之间的委托。文章还对比了使用构造函数与对象委托创建实例的差异,并详细解析了constructor属性的工作原理。此外,提到了如何通过Object.create()的第二个参数添加和配置新对象的属性,以及‘类’与‘委托’在JavaScript模拟类继承中的应用。
摘要由CSDN通过智能技术生成

Object.create()

我们常见的创建对象的方式有两种,一种是通过new Object(),一种是通过对象字面量的形式。而这里我们还会再介绍的另外一种方式 —— Object.create()

Object.create(null)

let empty_obj = {};
let better_empty_obj = Object.create(null);

console.log(empty_obj);   // {}  有__proto__属性
console.log(better_empty_obj);   // {}  无__proto__属性

通过 Object.create(null) 创建的对象没有 Object.prototype 这个委托,所以比 {} 更空

创建关联,制造委托(对象与对象之间)

Object.create()是一个大英雄,并不只是用来让我们生成一个更空的对象(哈哈)

let foo = {
  tell() {
    console.log('tell me something');
  }
};

let bar = Object.create(foo);

bar.tell();  // tell me something

创建一个空对象bar,并将这个对象的[[Prototype]]属性关联到foo对象,这样做和通过new一个构造函数都可以创建一个新对象,并使其[[Prototype]]属性关联到另一个对象,但是通过Object.create()的方式不会让新对象存在.constructor这样的引用(具体参看:关于constructor属性

更多参数

let foo = {
  a: 'aaa'
};

let bar = Object.create(foo, {
  b: {
    enumerable: false,
    writable: true,
    configurable: true,
    value: 'bbb'
  },
  c: {
    enumerable: true,
    writable: false,
    configurable: true,
    value: 'bbb'
  }
});

bar.hasOwnProperty('a')  // false
bar.hasOwnProperty('b')  // true
bar.hasOwnProperty('c')  // true

bar.a // aaa  
bar.b // bbb
bar.c // ccc

Object.create()的第二个参数可以为新对象增加新的属性(并可以通过属性描述符配置)

“类”与“委托”的对比

这里的类并不是说JS中有类的概念,只是模拟出这个感觉

第一段“类”代码

function Foo(who) {
  this.me = who;
}
Foo.prototype.identify = function() {
  return "I am " + this.me;
}

function Bar(who) {
  Foo.call(this, who);
}
// 创建委托关系
Bar.prototype = Object.create(Foo.prototype);
Bar.prototype.speak = function() {
  console.log('Hello, ' + this.identify());
}

var b1 = new Bar("b1");
var b2 = new Bar("b2");

b1.speak();  // Hello, I am b1
b2.speak();  // Hello, I am b2

console.log(b1.constructor);
console.log(b2.constructor);  
// ƒ Foo(who) {
//   this.me = who;
// }

console.log(Bar.prototype.constructor === b1.constructor);  // true
image-20210622150857613

第二段“委托”代码

let Foo = {
  init: function(who) {
    this.me = who;
  },
  identify: function () { 
    return "I am " + this.me;
  }
};

let Bar = Object.create(Foo);
Bar.speak = function() {
  console.log("Hello, " + this.identify());
}

var b1 = Object.create(Bar);
var b2 = Object.create(Bar);
b1.init('b1');
b2.init('b2');

b1.speak();  // Hello, I am b1
b2.speak();  // Hello, I am b2
image-20210622150946646

通过比较我们可以清晰的看出关联风格(“委托”)更加的简洁,因为代码只关注一件事,对象之间的关联

关于constructor属性

对于改动[[Prototype]]属性的原型对象来说,其constructor属性才会依据委托关系而改动!

先来分析一段代码

function Person() {

}

Person.prototype = {
  name: 'new obj'
};

let per = new Person();

console.log(per.constructor === Person);  // ?
console.log(per.constructor === Object);  // ?

这里的打印的值应该是什么?

我们先来看看下面这段代码

function Person() {

}

let per = new Person();

console.log(per.constructor === Person);  // true

通过图解:
image-20210615185822278

首先我们要明确的是,perconstructor属性是委托于(来自于)Person.Prototype对象

所以最上面的代码我们可以拆解为:

function Person() {

}

Person.prototype = new Object();
Person.prototype.name = 'new obj';

let per = new Person();

console.log(per.constructor === Person);  // false
console.log(per.constructor === Object);  // true
console.log(Person.prototype.constructor === Object);  // true

通过图解:
image-20210615190330317

所以per对象在获取constructor属性时,会沿着原型链一直往上寻找委托的constructor属性,直到此图中的Object.Prototype对象,所以打印结果如上面的代码

所以第一段代码中结果为:

console.log(per.constructor === Person);  // false
console.log(per.constructor === Object);  // true
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值