浏览代码

ES6-y the simple mix() method.

Piotrek Koszuliński 10 年之前
父节点
当前提交
03a030cc6c
共有 2 个文件被更改,包括 75 次插入9 次删除
  1. 8 9
      packages/ckeditor5-utils/src/utils.js
  2. 67 0
      packages/ckeditor5-utils/tests/utils.js

+ 8 - 9
packages/ckeditor5-utils/src/utils.js

@@ -110,8 +110,8 @@ const utils = {
 	},
 
 	/**
-	 * Copies enumerable properties from the objects given as 2nd+ parameters to the
-	 * prototype of the base class.
+	 * Copies enumerable properties and symbols from the objects given as 2nd+ parameters to the
+	 * prototype of first object (a constructor).
 	 *
 	 *		class SpecificEditor extends utils.mix( Editor, SomeMixin1, SomeMixin2 ) {
 	 *			...
@@ -122,14 +122,13 @@ const utils = {
 	 */
 	mix( baseClass, ...mixins ) {
 		mixins.forEach( ( mixin ) => {
-			Object.keys( mixin ).forEach( ( key ) => {
-				Object.defineProperty( baseClass.prototype, key, {
-					enumerable: false,
-					configurable: true,
-					writable: true,
-					value: mixin[ key ]
+			Object.getOwnPropertyNames( mixin ).concat( Object.getOwnPropertySymbols( mixin ) )
+				.forEach( ( key ) => {
+					const sourceDescriptor = Object.getOwnPropertyDescriptor( mixin, key );
+					sourceDescriptor.enumerable = false;
+
+					Object.defineProperty( baseClass.prototype, key, sourceDescriptor );
 				} );
-			} );
 		} );
 	}
 };

+ 67 - 0
packages/ckeditor5-utils/tests/utils.js

@@ -192,5 +192,72 @@ describe( 'utils', () => {
 			expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
 			expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
 		} );
+
+		it( 'copies setters and getters (with descriptors as of native classes)', () => {
+			class Foo {
+				set foo( v ) {
+					this._foo = v;
+				}
+				get foo() {}
+			}
+
+			const Mixin = {
+				set a( v ) {
+					this._a = v;
+				},
+				get a() {
+					return this._a;
+				}
+			};
+
+			utils.mix( Foo, Mixin );
+
+			const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'a' );
+			const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, 'foo' );
+
+			expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
+			expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
+
+			const foo = new Foo();
+
+			foo.a = 1;
+			expect( foo._a ).to.equal( 1 );
+
+			foo._a = 2;
+			expect( foo.a ).to.equal( 2 );
+		} );
+
+		it( 'copies symbols (with descriptors as of native classes)', () => {
+			const symbolA = Symbol( 'a' );
+			const symbolFoo = Symbol( 'foo' );
+
+			// https://github.com/jscs-dev/node-jscs/issues/2078
+			// jscs:disable disallowSpacesInFunction
+			class Foo {
+				[ symbolFoo ]() {
+					return 'foo';
+				}
+			}
+
+			const Mixin = {
+				[ symbolA ]() {
+					return 'a';
+				}
+			};
+			// jscs:enable disallowSpacesInFunction
+
+			utils.mix( Foo, Mixin );
+
+			const actualDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, symbolA );
+			const expectedDescriptor = Object.getOwnPropertyDescriptor( Foo.prototype, symbolFoo );
+
+			expect( actualDescriptor ).to.have.property( 'writable', expectedDescriptor.writable );
+			expect( actualDescriptor ).to.have.property( 'enumerable', expectedDescriptor.enumerable );
+			expect( actualDescriptor ).to.have.property( 'configurable', expectedDescriptor.configurable );
+
+			const foo = new Foo();
+
+			expect( foo[ symbolA ]() ).to.equal( 'a' );
+		} );
 	} );
 } );