一线大厂前端经典面试题JavaScript部分

你的名字 2022-12-10 10:08 334阅读 0赞

BAT笔试题中几道关于堆栈内存和闭包作用域的问题

  1. let a = {}, b = '0', c = 0;
  2. a[b] = 'JavaScript';
  3. a[c] = 'HTML+CSS';
  4. console.log(a[b]); //HTML+CSS
  5. //原因:对象中属性名不能重复,一般都为字符串属性,字符串属性名跟数字属性名是一样的
  6. let a = {}, b = Symbol('1'), c = Symbol('1');
  7. a[b] = 'JavaScript';
  8. a[c] = 'HTML+CSS';
  9. console.log(a[b]);//JavaScript
  10. //Symbol的特点是:创建的唯一值。Symbol('1')与Symbol('1')是不相等的
  11. let a = {},
  12. b = {
  13. n: '1'
  14. },
  15. c = {
  16. m: '2'
  17. }
  18. a[b] = 'JavaScript';
  19. a[c] = 'HTML+CSS';
  20. console.log(a[b]);//HTML+CSS
  21. //对象做属性名时会通过.toString方法被转换为字符串,而对象转换为字符串后都是"[object, Object]"
  22. // 所以b和c转换为字符串后是一样的。
  23. var test = (function(i){
  24. return function(){
  25. alert(i*=2);// alert输出结果都会转为字符串
  26. }
  27. })(2)
  28. test(5); // '4'
  29. //首先是创建一个自调用函数,在函数中又返回一个函数,这里有闭包产生。
  30. //立即执行函数接收的实参是2,然后返回一个函数。
  31. //这时test是一个无参函数,函数体就是alert(i*=2),由于闭包作用这里的i是立即执行函数的参数i,而立即执行函数执行时传入的参数是2
  32. //当调用test函数时虽然传了个参数5,但由于test是一个无参函数,因此5没有任何作用
  33. //所以最终结果是4,而又因alert会把内容转换为字符串,所以最终alert的是字符串4
  34. var a = 0, b = 0;
  35. function A(a){
  36. A = function(b){
  37. alert(a+b++);
  38. }
  39. alert(a++)
  40. }
  41. A(1); // "1"
  42. A(2); // "4"

对象(数组)的深克隆和浅克隆(头条)

  1. let obj = {
  2. a: 100,
  3. b: [10, 20, 30],
  4. c: {
  5. x: 10
  6. },
  7. d: /^\d+S/
  8. };
  9. let arr = [10, [100, 200], {
  10. x: 10,
  11. y: 20
  12. }];
  13. //=>浅克隆
  14. //es6
  15. let obj2 = {...obj};
  16. //es5
  17. let obj2 = {}
  18. for(let key in obj){
  19. if(obj.hasOwnProperty(key)){
  20. obj2[key] = obj[key];
  21. }
  22. }
  23. //=>深克隆
  24. //let obj2 = JSON.parse(JSON.stringify(obj));//先转成json字符串再转成对象,但是如果对象内部有函数,正则或日期则转换时会有问题
  25. function deepClone(obj){
  26. if(obj === null) return null;
  27. if(typeof obj !== "object") return obj;
  28. if(obj instanceof RegExp) return new RegExp(obj);
  29. if(obj instanceof Date) return new Date(obj);
  30. let cloneObj = new obj.constructor;
  31. for(let key in obj){
  32. if(obj.hasOwnProperty(key)){
  33. cloneObj[key] = deepClone(obj[key]);
  34. }
  35. }
  36. return cloneObj;
  37. }
  38. let obj2 = deepClone(obj);

一道关于面向对象面试题引发的血案(阿里)

  1. function Foo(){
  2. getName = function(){
  3. console.log(1);
  4. };
  5. return this;
  6. }
  7. Foo.getName = function(){
  8. console.log(2);
  9. }
  10. Foo.prototype.getName = function(){
  11. console.log(3);
  12. }
  13. var getName = function(){
  14. console.log(4);
  15. };
  16. function getName(){
  17. console.log(5);
  18. }
  19. Foo.getName();//2
  20. getName();//4
  21. Foo().getName();//1
  22. getName();//1
  23. new Foo.getName();//2
  24. new Foo().getName();//3
  25. new new Foo().getName();//3

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpeGlhb3Nlbmxpbg_size_16_color_FFFFFF_t_70

一道面试题让你彻底掌握JS中的EventLoop(头条)

  1. async function async1(){
  2. console.log('async1 start');
  3. await async2();
  4. console.log('async1 end');
  5. }
  6. async function async2(){
  7. console.log('async2');
  8. }
  9. console.log('script start');
  10. setTimeout(function(){
  11. console.log('setTimeout');
  12. },0);
  13. async1();
  14. new Promise(function(resolve){
  15. console.log('promise1');
  16. resolve();
  17. }).then(function(){
  18. console.log('promise2');
  19. });
  20. console.log('script end');

watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpeGlhb3Nlbmxpbg_size_16_color_FFFFFF_t_70 1

  1. function A(){
  2. alert(1);
  3. }
  4. function Func(){
  5. A = function(){
  6. alert(2);
  7. }
  8. return this;
  9. }
  10. Func.A = A;//相当于 Func.A = function(){alert(1)}
  11. Func.prototype = {
  12. A: () => {
  13. alert(3);
  14. }
  15. }
  16. A();//1
  17. Func.A();//1
  18. Func().A();//2 先调用Func函数,重写全局函数A并返回this(window),然后执行window.A(),此时A已经被重写,所以输出2
  19. new Func.A();//1
  20. new Func().A();//3 相当于实例.A(),所以去原型里找,输出3
  21. new new Func().A();//报错,原因是原型中的A是箭头函数,不支持new
  22. var x = 2;
  23. var y = {
  24. x: 3,
  25. z: (function(x){
  26. this.x *= x;
  27. x += 2;
  28. return function(n){
  29. this.x *= n;
  30. x += 3;
  31. console.log(x);
  32. }
  33. })(x)
  34. };
  35. var m = y.z;
  36. //y.z是自调用闭包函数,z函数自调用时传出的参数x值为全局x的值2,在函数内部执行x+=2后x变为4,然后返回一个函数。当调用m(4)时,实际上调用的是z返回的函数,此时n为4,x也为4,在执行x += 3后变为7所以输出7
  37. m(4);//7
  38. //当执行y.z(5)时,n的值为5,this.x *= n中this.x指的是y对象的x属性,值为3,执行*=n后变为15,
  39. //而函数中的x来自上级作用域中的x值为7,在执行完 +=3后变为10所以紧跟着console.log输出10
  40. y.z(5);//10
  41. //在执行完m(4)时window.x变为16, 而y.x在执行y.z(5)后变为15
  42. console.log(x, y.x);// 16, 15
  43. var x = 0, y = 1;
  44. function fn(){
  45. x += 2;
  46. fn = function(y){
  47. console.log(y + (--x));
  48. }
  49. console.log(x, y);
  50. }
  51. fn(3);//2,1 1.执行代码在fn中对x进行+=2操作,x变为2,2. fn重新指向另一个函数,3.输出x和y的值2,1
  52. fn(4);//5 fn已经指向另一个函数即console.log(y + (--x));y为传入的参数4,x则为上级作用域中的x值为2,自减后变为1 所以输出4+1=5
  53. console.log(x, y);//1,1 执行完上两个步骤后x变为1,全程未对全局变量y操作,所以y依然是1
  54. setTimeout(() => {
  55. console.log(1);
  56. }, 20);
  57. console.log(2);
  58. setTimeout(() => {
  59. console.log(3);
  60. }, 10);
  61. console.log(4);
  62. console.time("AA");
  63. for(let i = 0; i < 90000000; i++){
  64. //do somthing这里为了代码阻塞
  65. }
  66. console.timeEnd('AA');
  67. console.log(5);
  68. setTimeout(() => {
  69. console.log(6);
  70. }, 8);
  71. console.log(7);
  72. setTimeout(() => {
  73. console.log(8);
  74. }, 15);
  75. console.log(9);
  76. //结果输出:
  77. // 2 4 时间长 5 7 9 3 1 6 8
  78. //在代码从上到下执行时优先执行console.log/time/timeEnd,然后将setTimeout添加到宏任务列队中,在for循环阻塞前先加了两个setTimeout,阻塞后又加了2个。所以在主栈代码执行完成后开始执行列队中的任务,因为阻塞前的先添加进去的所以优先按顺序执行,然后再执行阻塞后的即后添加到列队中的。
  79. // 当a为何值时,下面的条件能够成立
  80. var a;
  81. if(a == 1 && a == 2 && a == 3){
  82. console.log('条件成立');
  83. }
  84. //在==进行比较时,对象会调用自身的toString方法转换为字符串后再转换为数字进行比较,所以可以利用这一点对toString进行重写以达到目的
  85. //1. 每比较一次都会调用一次toString,i就会加1,从而使条件成立
  86. var a = {
  87. i: 0,
  88. toString: function(){
  89. return ++i;
  90. }
  91. }
  92. //2. 利用数组的shift和对象的toString
  93. var a = [1, 2, 3];
  94. a.toString = a.shift;
  95. //3. 利用Object.defineProperty()来监听window对象的a属性并重写get方法
  96. //这里不用a是因为在get中进行自加时又会调用get方法导致死循环
  97. var i = 0;
  98. Object.defineProperty(window, 'a', {
  99. get: function(){
  100. return ++i;
  101. }
  102. });

发表评论

表情:
评论列表 (有 0 条评论,334人围观)

还没有评论,来说两句吧...

相关阅读