MSIPO技术圈 首页 IT技术 查看内容

JavaScript中的行为委托和面向类的区别?

2024-03-28

先复习一些原型链的知识:
[[Prototype]] 机制是一种存在于一个对象上的内部链接它指向一个其他对象
在JavaScript中,每个对象都有一个原型对象(prototype),当访问对象的属性或方法时,如果对象自身没有定义,它会沿着原型链向上查找直到找到对应的属性或方法。这种原型链的机制使得对象之间可以实现继承关系,从而可以共享原型对象上的属性和方法。

1. 行为委托

首先定义一个称为 Parent 的对象 (不是一个类,也不是function),让它拥有具体的行为。定义一个 对象来持有这个特定任务的数据 /行为。

const A = {
  setName:function(name){
    this.name = name
  },
  getName: function () {
    return 'my name is ' + this.name;
  },
}
// 使 B 委托到 A, B的[[protoType]]会指向A对象
const B = Object.create(A);//Object.create作用:以一个现有对象为原型创建一个新对象
B.greeting = function(){
  console.log('hello, '+this.getName());
}

//使 b1 委托到 B, b1的[[protoType]]会指向B对象
const b1 = Object.create(B);
// 通过原型链访问A对象上方法
b1.setName('b1');
//使 b2 委托到 B, b2的[[protoType]]会指向B对象
const b2 = Object.create(B);
b2.setName('b2');

// 通过原型链访问B对象上方法
b1.greeting()// hello, my name is b1
b2.greeting()// hello, my name is b2

行为委托意味着:在访问某个对象上不存在的属性或方法时,让这个对象为属性或方法引用提供一个委托。可以多级委托,但是不能相互委托,不能在两个或多个对象间相互地委托(双向地)对方来创建一个 循环 。比如使 B 链接到 A,然后试着让 A 链接到 B。

注意:要尽量避免在 [[Prototype]] 链的不同层级上有相同的命名,因为会出现遮蔽现象。

2. 原型连中的遮蔽

const oldObj = {
	a: 2
};

// newObj的[[protoType]]会指向 oldObj
const newObj = Object.create( oldObj );

console.log(oldObj.a);//2
console.log(newObj.a);//2 (查找原型链上的属性)

console.log(oldObj.hasOwnProperty( "a" ));// true
console.log(newObj.hasOwnProperty( "a" ));// false
newObj.a++;
console.log(oldObj.a);//2
console.log(newObj.a);//3 

console.log(oldObj.hasOwnProperty( "a" ));// true
console.log(newObj.hasOwnProperty( "a" ));// true (是自己的属性噢!竟然创建了一个新属性!!)

虽然看起来 newObj.a++ 应当(通过委托)查询并原地递增 oldObj.a 属性,但是 ++ 操作符相当于 newObj.a = newObj.a + 1。
newObj.a + 1 是在[[Prototype]] 上进行 a 的 [[Get]]查询,从 oldObj.a 得到当前的值 2,将这个值递增1。然后将这个值 3 用 [[Put]]赋值给 newObj 上的新遮蔽属性 a上。
如果想递增 oldObj.a,唯一正确的方法是 oldObj.a++

3. 面向类

实现与行为委托例子一样的行为:

function A(name){
  this.name = name
}
A.prototype.getName = function (){
  return 'my name is ' + this.name
}
function B(name){
  // this的显式绑定:this指向A,并调用A函数初始化name
  A.call(this,name)
}
// B继承A
// 将A.prototype对象作为B的原型对象,B.prototype继承了A.prototype的属性和方法
B.prototype = Object.create(A.prototype);
B.prototype.greeting = function(){
  console.log('hello, '+this.getName());
}
// 调用 B函数,创建一个新对象b1,并将this指向b1
const b1 = new B('b1');
const b2 = new B('b2');

b1.greeting();// hello, my name is b1
b2.greeting();// hello, my name is b2

在 JS 中,构造器 仅仅是一个函数,它们偶然地与前置的 new 操作符一起调用。它们不依附于类,它们也不初始化一个类。它们甚至不是一种特殊的函数类型。它们本质上只是一般的函数,在被使用 new 来调用时改变做了附加的行为。(创建一个新对象,并将this指向这个新对象)

4. 行为委托和面向类的区别

  1. 对象关系:
  • 行为委托: 在行为委托中,对象之间是对等的,它们彼此通过委托来共享和重用代码。对象之间的关系是动态的,一个对象可以将请求委托给另一个对象来处理,而不是通过类和继承来建立父子关系。
  • 面向类: 在基于类的继承中,通常存在明确的父类和子类之间的关系。子类继承父类的属性和方法,并且可以添加或修改这些属性和方法。对象之间的关系是静态的,由类定义决定,在对象创建时就确定了
  1. 代码组织方式:
  • 行为委托: 在行为委托中,代码的组织方式更加灵活,因为对象之间的关系是动态的。对象通过委托来共享和重用代码,使得代码更具可组合性和灵活性。
  • 面向类: 在基于类的继承中,代码通常是通过类来组织的,对象之间的关系由类的层次结构确定。虽然类继承提供了一种组织和复用代码的方式,但它也可能导致类层次结构的复杂性和深层次的继承链
  1. 继承机制:
  • 行为委托: 在行为委托中,对象之间通过委托共享和重用代码,而不是通过继承。
  • 面向类: 在基于类的继承中,子类继承父类的属性和方法,并且可以通过继承来共享和重用代码。继承是通过类和类之间的关系来实现的,子类可以扩展或修改父类的行为。

相关阅读

热门文章

    手机版|MSIPO技术圈 皖ICP备19022944号-2

    Copyright © 2024, msipo.com

    返回顶部