s-function.js 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. describe('Function', function () {
  2. 'use strict';
  3. describe('#apply()', function () {
  4. it('works with arraylike objects', function () {
  5. var arrayLike = { length: 4, 0: 1, 2: 4, 3: true };
  6. var expectedArray = [1, undefined, 4, true];
  7. var actualArray = (function () {
  8. return Array.prototype.slice.apply(arguments);
  9. }.apply(null, arrayLike));
  10. expect(actualArray).toEqual(expectedArray);
  11. });
  12. });
  13. describe('#bind()', function () {
  14. var actual;
  15. var testSubject = {
  16. push: function (o) {
  17. this.a.push(o);
  18. }
  19. };
  20. var func = function func() {
  21. Array.prototype.forEach.call(arguments, function (a) {
  22. this.push(a);
  23. }, this);
  24. return this;
  25. };
  26. beforeEach(function () {
  27. actual = [];
  28. testSubject.a = [];
  29. });
  30. it('binds properly without a context', function () {
  31. var context;
  32. testSubject.func = function () {
  33. context = this;
  34. }.bind();
  35. testSubject.func();
  36. expect(context).toBe(function () { return this; }.call());
  37. });
  38. it('binds properly without a context, and still supplies bound arguments', function () {
  39. var a, context;
  40. testSubject.func = function () {
  41. a = Array.prototype.slice.call(arguments);
  42. context = this;
  43. }.bind(undefined, 1, 2, 3);
  44. testSubject.func(1, 2, 3);
  45. expect(a).toEqual([1, 2, 3, 1, 2, 3]);
  46. expect(context).toBe(function () { return this; }.call());
  47. });
  48. it('binds a context properly', function () {
  49. testSubject.func = func.bind(actual);
  50. testSubject.func(1, 2, 3);
  51. expect(actual).toEqual([1, 2, 3]);
  52. expect(testSubject.a).toEqual([]);
  53. });
  54. it('binds a context and supplies bound arguments', function () {
  55. testSubject.func = func.bind(actual, 1, 2, 3);
  56. testSubject.func(4, 5, 6);
  57. expect(actual).toEqual([1, 2, 3, 4, 5, 6]);
  58. expect(testSubject.a).toEqual([]);
  59. });
  60. it('returns properly without binding a context', function () {
  61. testSubject.func = function () {
  62. return this;
  63. }.bind();
  64. var context = testSubject.func();
  65. expect(context).toBe(function () { return this; }.call());
  66. });
  67. it('returns properly without binding a context, and still supplies bound arguments', function () {
  68. var context;
  69. testSubject.func = function () {
  70. context = this;
  71. return Array.prototype.slice.call(arguments);
  72. }.bind(undefined, 1, 2, 3);
  73. actual = testSubject.func(1, 2, 3);
  74. expect(context).toBe(function () { return this; }.call());
  75. expect(actual).toEqual([1, 2, 3, 1, 2, 3]);
  76. });
  77. it('returns properly while binding a context properly', function () {
  78. var ret;
  79. testSubject.func = func.bind(actual);
  80. ret = testSubject.func(1, 2, 3);
  81. expect(ret).toBe(actual);
  82. expect(ret).not.toBe(testSubject);
  83. });
  84. it('returns properly while binding a context and supplies bound arguments', function () {
  85. var ret;
  86. testSubject.func = func.bind(actual, 1, 2, 3);
  87. ret = testSubject.func(4, 5, 6);
  88. expect(ret).toBe(actual);
  89. expect(ret).not.toBe(testSubject);
  90. });
  91. it('has the new instance\'s context as a constructor', function () {
  92. var actualContext;
  93. var expectedContext = { foo: 'bar' };
  94. testSubject.Func = function () {
  95. actualContext = this;
  96. }.bind(expectedContext);
  97. var result = new testSubject.Func();
  98. expect(result).toBeTruthy();
  99. expect(actualContext).not.toBe(expectedContext);
  100. });
  101. it('passes the correct arguments as a constructor', function () {
  102. var expected = { name: 'Correct' };
  103. testSubject.Func = function (arg) {
  104. expect(Object.prototype.hasOwnProperty.call(this, 'name')).toBe(false);
  105. return arg;
  106. }.bind({ name: 'Incorrect' });
  107. var ret = new testSubject.Func(expected);
  108. expect(ret).toBe(expected);
  109. });
  110. it('returns the return value of the bound function when called as a constructor', function () {
  111. var oracle = [1, 2, 3];
  112. var Subject = function () {
  113. expect(this).not.toBe(oracle);
  114. return oracle;
  115. }.bind(null);
  116. var result = new Subject();
  117. expect(result).toBe(oracle);
  118. });
  119. it('returns the correct value if constructor returns primitive', function () {
  120. var Subject = function (oracle) {
  121. expect(this).not.toBe(oracle);
  122. return oracle;
  123. }.bind(null);
  124. var primitives = ['asdf', null, true, 1];
  125. for (var i = 0; i < primitives.length; ++i) {
  126. expect(new Subject(primitives[i])).not.toBe(primitives[i]);
  127. }
  128. var objects = [[1, 2, 3], {}, function () {}];
  129. for (var j = 0; j < objects.length; ++j) {
  130. expect(new Subject(objects[j])).toBe(objects[j]);
  131. }
  132. });
  133. it('returns the value that instance of original "class" when called as a constructor', function () {
  134. var ClassA = function (x) {
  135. this.name = x || 'A';
  136. };
  137. var ClassB = ClassA.bind(null, 'B');
  138. var result = new ClassB();
  139. expect(result instanceof ClassA).toBe(true);
  140. expect(result instanceof ClassB).toBe(true);
  141. });
  142. it('sets a correct length without thisArg', function () {
  143. var Subject = function (a, b, c) { return a + b + c; }.bind();
  144. expect(Subject.length).toBe(3);
  145. });
  146. it('sets a correct length with thisArg', function () {
  147. var Subject = function (a, b, c) { return a + b + c + this.d; }.bind({ d: 1 });
  148. expect(Subject.length).toBe(3);
  149. });
  150. it('sets a correct length with thisArg and first argument', function () {
  151. var Subject = function (a, b, c) { return a + b + c + this.d; }.bind({ d: 1 }, 1);
  152. expect(Subject.length).toBe(2);
  153. });
  154. it('sets a correct length without thisArg and first argument', function () {
  155. var Subject = function (a, b, c) { return a + b + c; }.bind(undefined, 1);
  156. expect(Subject.length).toBe(2);
  157. });
  158. it('sets a correct length without thisArg and too many argument', function () {
  159. var Subject = function (a, b, c) { return a + b + c; }.bind(undefined, 1, 2, 3, 4);
  160. expect(Subject.length).toBe(0);
  161. });
  162. });
  163. });