设计模式(7)[JS版]-JavaScript设计模式之原型模式如何实现???

举报
AlbertYang 发表于 2021/02/02 23:16:24 2021/02/02
5.6k+ 0 0
【摘要】 目录 1.什么是原型模式 2 参与者 3 实例讲解 4 使用 Object.create实现原型模式 4.1 Object.create()的用法 4.2 用 Object.create实现继承 4.2.1 单继承 4.2.2 多继承   4.3 propertyObject参数 4.4 Polyfill 4.5 改写原型模式实现 5 总结 1.什...

目录

1.什么是原型模式

2 参与者

3 实例讲解

4 使用 Object.create实现原型模式

4.1 Object.create()的用法

4.2 用 Object.create实现继承

4.2.1 单继承

4.2.2 多继承 

 4.3 propertyObject参数

4.4 Polyfill

4.5 改写原型模式实现

5 总结


1.什么是原型模式

原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象。 原型模式不单是一种设计模式,也被称为一种编程泛型。 从设计模式的角度讲,原型模式是用于创建对象的一种模式。我们不再关心对象的具体类型,而是找到一个对象,然后通过克隆来创建一个一模一样的对象。在其他语言很少使用原型模式,但是JavaScript作为原型语言,在构造新对象及其原型时会使用该模式。

2 参与者

原型模式的主要参与者有

客户端( Client) : 通过要求一个原型克隆自己来创建一个新的对象。

原型( Prototype) :创建一个接口来克隆自己

克隆( Clones ) :正在创建的克隆对象

3 实例讲解

在示例代码中,我们有一个CustomerPrototype对象,它可以克隆给定原型对象(Customer)。它的构造函数接受一个Customer类型的原型,然后调用克隆方法生成一个新的Customer对象,其对象属性值使用原型对象的值进行初始化。

这是原型模式的经典实现,但JavaScript可以使用其内置的原型更有效地实现这一功能,后边我们将会修改这一代码


        <!DOCTYPE html>
        <html>
       	<head>
       		<meta charset="utf-8">
       		<title>JS原型模式:公众号AlbertYang</title>
       	</head>
       	<body>
       	</body>
       	<script>
       		//客户原型类
       		function CustomerPrototype(proto) {
       			this.proto = proto;
       			this.clone = function() {
        var customer = new Customer();
         customer.name = proto.name;
         customer.age = proto.age;
        return customer;
        			};
        		}
       		//客户类
       		function Customer(name, age) {
       			this.name = name;
       			this.age = age;
       			this.say = function() {
        console.info("%c%s", "color:red;font-size:18px", "姓名: " + this.name + ", 年龄: " + this.age);
        			};
        		}
       		function run() {
       			var proto = new Customer("张三", 18);
       			var prototype = new CustomerPrototype(proto);
       			var customer = prototype.clone();
        			customer.say();
        		}
        		run();
       	</script>
        </html>
    
   

4 使用 Object.create实现原型模式

在现有的文献里查看原型模式的定义,没有针对JavaScript的,你可能发现很多讲解的都是关于类的,但是现实情况是基于原型继承的JavaScript完全避免了类(class)的概念。我们只是简单从现有的对象进行拷贝来创建对象。

在新版的ECMAScript5标准中提出,使用Object.create方法来创建指定的对象,其对象的prototype有指定的对象(也就是该方法传进的第一个参数对象),也可以包含其他可选的指定属性。例如Object.create(prototype, optionalDescriptorObjects)。

4.1 Object.create()的用法

Object.create()方法用于创建一个新对象,使用现有的对象来提供新创建的对象的__proto__。

语法:

Object.create(proto[, propertiesObject])
  

参数:

proto新创建对象的原型对象。

propertiesObject可选。如果没有指定为 undefined,则是要添加到新创建对象的不可枚举(默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。

返回值:一个新对象,带着指定的原型对象和属性。

4.2 用 Object.create实现继承

下面的例子演示了如何使用Object.create()来实现类式继承。这是所有JavaScript版本都支持的单继承。

4.2.1 单继承


       <!DOCTYPE html>
       <html>
      	<head>
      		<meta charset="utf-8">
      		<title>JS原型模式:公众号AlbertYang</title>
      	</head>
      	<body>
      	</body>
      	<script>
      		// 父类
      		function Shape() {
      			this.x = 0;
      			this.y = 0;
       		}
      		// 父类的方法
       		Shape.prototype.move = function(x, y) {
      			this.x += x;
      			this.y += y;
      			console.info('Shape moved.');
       		};
      		// 子类
      		function Rectangle() {
       			Shape.call(this); // call方法用来调用父类Shape的构造函数
       		}
      		// 子类继承父类
       		Rectangle.prototype = Object.create(Shape.prototype);
      		//重新指定构造函数
       		Rectangle.prototype.constructor = Rectangle;
       console.log(Rectangle);
      		var rect = new Rectangle();
      		console.log(rect);
      		console.log('rect是Rectangle的实例吗?',
       			rect instanceof Rectangle); // true
      		console.log('rect是Shape的实例吗?',
       			rect instanceof Shape); // true
       		rect.move(1, 1); // 输出, 'Shape moved.'
      	</script>
       </html>
   
  

4.2.2 多继承 

如果你希望能继承到多个对象,则可以使用混入的方式。


      function MyClass() {
      	SuperClass.call(this);
      	OtherSuperClass.call(this);
      }
      // 继承一个类
      MyClass.prototype = Object.create(SuperClass.prototype);
      // 混合其它类
      Object.assign(MyClass.prototype, OtherSuperClass.prototype);
      // 重新指定constructor
      MyClass.prototype.constructor = MyClass;
      MyClass.prototype.myMethod = function() {
     	// 。。。。。
      };
  
 
 

Object.assign 会把 OtherSuperClass原型上的函数拷贝到 MyClass原型上,使 MyClass 的所有实例都可以使用 OtherSuperClass 的方法。Object.assign 是在 ES2015 引入的,且可用 polyfilled。要支持旧浏览器的话,可用使用 jQuery.extend() 或者 _.assign()。

 4.3 propertyObject参数


      <script>
     	var o;
     	// 创建一个原型为null的空对象
      	o = Object.create(null);
      	o = {};
     	// 上面的一句就相当于:
      	o = Object.create(Object.prototype);
      	o = Object.create(Object.prototype, {
     		// foo会成为所创建对象的数据属性
     		foo: {
     			writable: true,
     			configurable: true,
     			value: "hello"
      		},
     		// bar会成为所创建对象的访问器属性
     		bar: {
     			configurable: false,
     			get: function() {
      return 10
      			},
     			set: function(value) {
      console.log("Setting `o.bar` to", value);
      			}
      		}
      	});
     	function Constructor() {}
      	o = new Constructor();
     	// 上面的一句就相当于:
      	o = Object.create(Constructor.prototype);
     	// 如果在Constructor函数中有一些初始化代码,Object.create不能执行那些代码
     	// 创建一个以另一个空对象为原型,且拥有一个属性p的对象
      	o = Object.create({}, {
     		p: {
     			value: 42
      		}
      	})
     	// 省略了的属性特性默认为false,所以属性p是不可写,不可枚举,不可配置的:
      	o.p = 24
     	console.log(o.p) //42
      	o.q = 12
     	for (var prop in o) {
     		console.log(prop); //q
      	}
     	delete o.p //false
     	//创建一个可写的,可枚举的,可配置的属性p
      	o2 = Object.create({}, {
     		p: {
     			value: 42,
     			writable: true,
     			enumerable: true,
     			configurable: true
      		}
      	});
      </script>
  
 

4.4 Polyfill

Polyfill 是一块代码(通常是 Web 上的 JavaScript),用来为旧浏览器提供它没有原生支持的较新的功能。比如说 polyfill 可以让 IE7 使用 Silverlight 插件来模拟 HTML Canvas 元素的功能,或模拟 CSS 实现 rem 单位的支持,或或 text-shadow,或其他任何你想要的功能。

下边这个 polyfill 涵盖了Object.create主要的应用场景,它创建一个已经选择了原型的新对象,但没有把第二个参数考虑在内。尽管在 ES5 中 Object.create支持设置为[[Prototype]]null,但因为JS以前一些老版本的限制,此 polyfill 无法支持该特性。


      if (typeof Object.create !== "function") {
      Object.create = function (proto, propertiesObject) {
      if (typeof proto !== 'object' && typeof proto !== 'function') {
      throw new TypeError('Object prototype may only be an Object: ' + proto);
       } else if (proto === null) {
      throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
       }
      if (typeof propertiesObject !== 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
      function F() {}
       F.prototype = proto;
      return new F();
       };
      }
  
 

4.5 改写原型模式实现


       <!DOCTYPE html>
       <html>
      	<head>
      		<meta charset="utf-8">
      		<title>JS原型模式:公众号AlbertYang</title>
      	</head>
      	<body>
      	</body>
      	<script>
      		// 因为不是构造函数(类),所以不用大写
      		var customer = {
       name:'',
      			age:'',
      			say: function() {
       console.info("%c%s", "color:red;font-size:18px", "姓名: " + this.name + ", 年龄: " + this.age);
       			}
       		};
      		function run() {
       // 使用Object.create创建一个新客户
      			var myCustomer = Object.create(customer);
       			myCustomer.name = '张三';
       			myCustomer.age = '18';
       			myCustomer.say();
       		}
       		run();
      	</script>
       </html>
   
  

5 总结

原型模式在JavaScript里的使用简直是无处不在,其它很多模式有很多也是基于prototype的,大家使用的时候要注意浅拷贝和深拷贝的问题,免得出现引用问题。

今天的学习就到这里,你可以使用今天学习的技巧来改善一下你曾经的代码,如果想继续提高,欢迎关注我,每天学习进步一点点,就是领先的开始。如果觉得本文对你有帮助的话,欢迎点赞,评论,转发!!!

文章来源: albertyang.blog.csdn.net,作者:Albert Yang,版权归原作者所有,如需转载,请联系作者。

原文链接:albertyang.blog.csdn.net/article/details/107622223

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

作者其他文章

评论(0

抱歉,系统识别当前为高风险访问,暂不支持该操作

    全部回复

    上滑加载中

    设置昵称

    在此一键设置昵称,即可参与社区互动!

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

    *长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。