写点什么

六大类型 JavaScript 题型

作者:不叫猫先生
  • 2023-06-16
    北京
  • 本文字数:5005 字

    阅读完需:约 16 分钟

六大类型JavaScript题型

1、原型和原型链

当我们找实例对象的属性时,如果找不到,就会查找与对象关联的原型中去找,如果还找不到,就去找原型的原型,直到最顶层。


function A() {}function B(a) {    this.a = a;}function C(a) {    if (a) {        this.a = a;    }}A.prototype.a = 1;B.prototype.a = 1;C.prototype.a = 1;console.log(new A().a);console.log(new B().a);console.log(new C(2).a);
复制代码


答案:1 undefined 2


解析:



//声明一个构造函数Afunction A() {}//声明一个构造函数B,传人参数a,自有属性a的值取决于传入的参数function B(a) { this.a = a;}//声明一个构造函数B,如果有参数,则添加自有属性a,属性a的值为传入的参数值,//如果没有传入参数,则构造函数C没有自有属性function C(a) { if (a) { this.a = a; }}A.prototype.a = 1;B.prototype.a = 1;C.prototype.a = 1;//构造函数function A(){},是没有自有属性的,然后就会顺着原型链查找,我们找到构造函数A的原型对象A.prototype上有属性a且等于1console.log(new A().a);//1console.log(new B().a);//undefinedconsole.log(new C(2).a);//2
复制代码

2、异步队列

微任务:Promise.then、async/await、MutaionObserver 宏任务:script(整体)、setTimeout、setInterval、Ajax、DOM 事件、postMessage 执行顺序如下:



  • 第一题


  async function async1() {    console.log("a");    const res = await async2();    console.log("b");   }    async function async2() {     console.log("c");     return 2;    }
console.log("d"); setTimeout(() => { console.log("e"); }, 0); async1().then(res => { console.log("f") }) new Promise((resolve) => { console.log("g"); resolve(); }).then(() => { console.log("h"); }); console.log("i");
复制代码


答案:d、a、c、g、i、b、h、f、e


解析:


//打印d//遇到setTimeout,放到宏任务队列//遇到async1().then(),先执行async1(),then函数注册到微任务队列(但不是立即注册,而是等async1()执行完之后才会注册)//在执行async1()时候  async1().then(res => {      console.log("f")  })//打印a//执行async1()时,当执行到 const res = await async2()时,await后先让后面的表达式先执行,也就是async2()//打印c//然后将其后面的代码放到微任务队列中,然后跳出async函数,执行后面的代码,console.log("c")被放到了微任务队列中//执行new Promise((resolve) => { console.log("g"); resolve();  }).then(),由于new Promise()是同步任务//打印g//new Promise后的then函数放到微任务队列//打印i//此时微任务队列[console.log("b"),console.log("h")][console.log("f")]//宏任务队列[console.log("e")]//先执行微任务,再执行宏任务//打印g、f、e
复制代码


  • 第二题


setTimeout(function(){    console.log(1)  },0)
new Promise(function(resolve,reject){ console.log(2) for(var i=0;i<10000;i++) { if(i===10){ console.log(10); } i==9999 && resolve() } console.log(3); }).then(function(){ console.log(4); }) console.log(5);
复制代码


答案:2 10 3 5 4 1


解析


//setTimeout放到宏任务队列//执行 new Promise()同步任务//打印2//打印10//打印3// new Promise()后的then函数 放到微任务队列//打印5微任务队列:[console.log(4)]宏任务队列:[ console.log(1)]
复制代码


  • 第三题


Promise.reject(1).      then(2).      then(res => { return 3 }).      catch(error => { return 4 }).      then(Promise.resolve(5)).      then(console.log)
复制代码


答案:4 解析:


//Promise.reject(1) 返回一个被拒绝的 Promise,其拒绝原因为数字 1。//.then(2) 返回一个新的 Promise,它的回调函数不会被调用,因为前一个 Promise 被拒绝了。//.then(res => { return 3 }) 返回一个新的 Promise,它的回调函数也不会被调用,因为前一个 Promise 被拒绝了。//.catch(error => { return 4 }) 返回一个新的 Promise,它的回调函数被调用并返回数字 4(作为一个被解决的 Promise)。//.then(Promise.resolve(5)) 返回一个新的 Promise,它的回调函数不会被调用,因为参数不是一个函数。//.then(console.log) 返回一个新的 Promise,它的回调函数被调用并打印数字 4。
复制代码


  • 第四题


var F = function() {};Object.prototype.a = function() {  console.log("a()");};Function.prototype.b = function() {  console.log("b()");};var f = new F();F.a();F.b();f.a();f.b();
复制代码


答案:a b a f.b is not a function


解析:


//1、声明变量F,F既是对象也是函数,故F可调用原型上的方法,无论是对象还是函数上的//2、f = new F(),通过 构造函数 F new了一个实例f,此f只是一个对象并不是函数类型,故不能调用Function原型上的方法//证明:
复制代码


3、浅拷贝/深拷贝

浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存深拷贝生成一个新对象,新对象跟原对象不共享内存,修改新对象不会改到原对象


  • 第一题


var obj1 = {    a:  1,    b:  2,    c:  3}var obj2 = obj1;obj2.a = 5;console.log(obj1.a);  console.log(obj2.a);
复制代码


答案:1 5


解析


//var obj2 = obj1属于浅拷贝,故而obj1,obj2共用一个内存,打印出5,5
复制代码


  • 第二题


var obj1 = {a: 1,b: 2,c: 3}var objString = JSON.stringify(obj1);var obj2 = JSON.parse(objString);obj2.a = 5;console.log(obj1.a);console.log(obj2.a);
复制代码


解析


//JSON.stringify() 方法将一个 JavaScript 对象或值转换为 JSON 字符串//JSON.parse() 方法用来解析 JSON 字符串,解析为 JavaScript 值或对象//JSON.parse(JSON.stringify())也常被用作深拷贝//深拷贝生成一个新对象,新对象跟原对象不共享内存,修改新对象不会改到原对象//打印1、5
复制代码


  • 第三题


       let obj = {      num: 117    }    var num = 935;    function func() {      console.log(this.num)    }    const wrapper = func.bind(obj);    setTimeout(() => {      wrapper()    }, 1000)    obj = {      num: 130    }
复制代码


答案:117


解析:


//在执行const wrapper = func.bind(obj)时,func的this指向obj//接着执行setTimeout,1s后执行wrapper//在上面的一秒内,重新赋值obj = {num:130},这并不会影响到已经绑定了 obj 的 wrapper 函数//所以打印出117
复制代码

4、作用域

JS 代码的执行是由浏览器中的 JS 解析器来执行的。JS 解析器执行 JS 代码的时候,分为两个过程:预解析过程,代码执行过程预解析过程:


1、把变量的声明提升到当前作用域的最前面,只会提升声明,不会提升赋值。2、把函数的声明提升到当前作用域的最前面,只会提升声明,不会提升调用。3、先提升 var,在提升 function。


预解析顺序:


1、预解析的顺序是从上到下,函数的优先级高于变量,函数声明提前到当前作用域最顶端,在 var 之上。2、函数执行的时候,函数内部才会进行预解析,如果有参数,先给实参赋值再进行函数内部的预解析。3、预解析函数是声明+定义(开辟了内存空间,形参值默认是 undefined)。4、预解析变量是只声明,不赋值,默认为 undefined。5、==<font color=red >函数重名时,后者会覆盖前者。 </font>==6、==<font color=red >变量重名时,不会重新声明,但是执行代码的时候会重新赋值。</font>==7、变量和函数重名的时候,函数的优先级高于变量


函数执行顺序:


1、形成私有作用域 2、形参赋值(也是私有变量)3、变量提升 4、代码从上到下执行 5、作用域是否销毁


函数作用域不销毁的条件:


1、函数的返回值为引用类型 2、返回值被其他变量使用


  • 第一题


var a = 0, b = 0function A(a) {  A = function(b) {    console.log(a + b++)  }  console.log(a++)}A(1)A(2)
复制代码


答案:2 4


解析


//执行A(1),传入参数1//修改函数A的值为:function(b) { console.log(a + b++) }// 执行 console.log(a++),打印出1
//执行A(2),传入参数2//由于A函数被修改,所以执行的的是function(b) { console.log(a + b++) }// 此时a为2,传入的b为2 ,所以打印4
复制代码


  • 第二题


console.log(a);  var a=12;function fn(){    console.log(a);        a=13;  }    fn();console.log(a); 
复制代码


答案:undefined 12 13


解析:


//如果在函数中定义变量时,如果不添加var关键字, 这个变量是一个全局变量 //打印undefined//由于a=13在定义a变量没有用关键字,所以在这里是全局变量//fn执行console.log(a)时没有找到私有变量a,会沿着作用域链查找变量//打印12//紧接着a=13修改全局变量//打印13
复制代码


  • 第三题



console.log(a); a=2;function fn(){ console.log(a); a=3; } fn();console.log(a);
复制代码


答案:Uncaught ReferenceError: a is not defined


解析:


//变量a不会被提升,因为没有var声明,//如果在函数中定义变量时,如果不添加var关键字, 这个变量是一个全局变量 //所以会报错:Uncaught ReferenceError: a is not defined
复制代码


  • 第四题



var a=10,b=11,c=12; function test(a){ a=1;var b=2;c=3; } test(10);alert(a); alert(b); alert(c);
复制代码


答案:1 11 3


  • 第五题


var foo = function () {    console.log("foo1")}foo()
var foo = function () { console.log("foo2")}foo()

function foo() { console.log("foo1")}foo()
function foo() { console.log("foo2")}foo()
复制代码


答案:foo1 foo2 foo2 foo2


解析:


//该题可以把代码分开var foo = function () {    console.log("foo1")}foo()
var foo = function () { console.log("foo2")}foo()
//1、声明了变量foo,因为声明变量重名了,故不会重新声明,//2、执行代码时候,会先执行function () { console.log("foo1")}//3、又对变量进行重新复制,故执行function () { console.log("foo2")}//所以打印出 foo1 foo2----------------------------------------function foo() { console.log("foo1")}foo()
function foo() { console.log("foo2")}foo()//1、在预解析的时候,由于声明函数foo重名,故后者会覆盖前者,所以最后foo函数声明的结果如下function foo() { console.log("foo2")}//2、执行打印出foo2 foo2
复制代码

5、矩阵转置

将 [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ]——>[ [1, 4, 7], [2, 5, 8], [3, 6, 9] ]


let a = [  [1,2,3],  [4,5,6],  [7,8,9]]let b = [  [1,4,7],  [2,5,8],  [3,6,9]]//其实不难发现 a[0][0] = b[0][0],a[0][1] = b[1][0],a[0][2] = b[2][0]//也就是 a[i][j] = b[j][i]
复制代码


解析:


function transposeArray(array) {  // 获取原行数和列数   const rows = array.length;  const cols = array[0].length;   // 创建一个新的二维数组,长度等于原来数组列数  const transposedArray = [];  for (let j = 0; j < cols; j++) {    transposedArray[j] = new Array(rows);  }  // 将元素从原数组复制到新数组中   for (let i = 0; i < rows; i++) {    for (let j = 0; j < cols; j++) {      transposedArray[j][i] = array[i][j];    }  }  return transposedArray;}const myArray = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];const transposedArray = transposeArray(myArray);console.log(transposedArray);// 输出:[[1, 4, 7], [2, 5, 8], [3, 6, 9]]
复制代码

6、类、继承

       class cls{      constructor(){        this.show()      }      show(){        console.log("yoo")      }    }    class son extends cls{      constructor(){        super()      }      show(){        console.log('ohh')      }    }    new son()    new cls()
复制代码


答案:ohh yoo


解析


//1、在创建 son 对象时,会先调用父类 cls 的构造函数//2、然后再调用子类 son 的构造函数。//3、在子类 son 的构造函数中,没有显式调用父类的 show 方法,因此会直接执行子类中重写的 show 方法,输出 “ohh”。//4、接着创建 cls 对象时,同样会调用父类 cls 的构造函数,执行父类的 show 方法,输出 “yoo”
复制代码


发布于: 13 分钟前阅读数: 3
用户头像

还未添加个人签名 2022-10-18 加入

前端领域优质创作者、阿里云专家博主,专注于前端各领域技术,共同学习共同进步,一起加油呀!

评论

发布
暂无评论
六大类型JavaScript题型_JavaScript_不叫猫先生_InfoQ写作社区