js 高频面试题详解

一:js 中的变量提升

例1

a = 2;
var a;
console.log(a);

答:2

解析:它会将当前作用域的所有变量的声明提升到程序的顶部,上述代码等价为:

var a;
 a = 2
console.log(a); // 2

例2:

console.log(a);// undefined 
var a = 2;

解析:变量的声明提升到程序的顶部;等价于:

var a;
console.log(a); 
a = 2;

问题:为什么会有变量提升?

其实啊,js和其他语言一样,都要经历编译和执行阶段,而在编译的时候,会搜集所有的变量并且在本作用域内提前声明,而且其他代码都不会改变顺序。

1:作用域:除了函数外,js是没有块级作用域

2:作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量。 注意:如果内部有,优先查找到内部,如果内部没有就查找外部的。

3:js的变量声明:js的变量声明其实大体上可以分为三种:var声明、let与const声明和函数声明。

函数声明与其他声明一起出现的时候,是以谁为准呢?答案就是,函数声明高于一切,毕竟函数是js的第一公民。

所以下面函数的调用会输出谁呢? 答案是  foo

foo();
function foo() {
    console.log('foo');
}
var foo = 2;

那么下面又会输出谁呢?

foo();
 
function foo() {
    console.log('1');
}
 
function foo() {
    console.log('2');
}

答案是: 2  因为有多个函数声明的时候,是由最后面的函数声明来替代前面的。

那下列程序优惠输出什么呢?

foo();
 
var foo = function() {
    console.log('foo');
}

答案是报了Uncaught TypeError: foo is not a function 的异常

二:js 的作用域问题

1. 除了函数外,js是没有块级作用域。
2. 作用域链:内部可以访问外部的变量,但是外部不能访问内部的变量。
注意:如果内部有,优先查找到内部,如果内部没有就查找外部的。
3. 注意声明变量是用var还是没有写(window.)
4. 注意:js有变量提升的机制【变量悬挂声明】
5. 优先级:声明变量 > 声明普通函数 > 参数 > 变量提升

例1:

function c(){
var b=2
    function a(){
         console.log(b); // undefind
         var b=3
         console.log(b); // 3
   }
   a()
   console.log(b); // 2
 }
c()

 例2:

var name = 'a';
(function(){
    if( typeof name == 'undefined' ){
        var name = 'b';
        console.log('111'+name);
    }else{
        console.log('222'+name);
    }
})()

答案: 111b

 例3:

function fun( a ){
    var a = 10;
    function a(){}
    console.log( a );
}
 
fun( 100 );

答案: 10

三:js的对象考题

 例1:创建对象的三种方式

1:利用字面变量创建
var obj = {
       uname: '张三疯',
       age: 18,
       sex: '男',
       sayHi: function() {
             console.log('hi~');

         }
  }
2:new object 创建对象
var obj = new Object(); // 创建了一个空的对象
obj.uname = '张三疯';
 obj.age = 18;
 obj.sex = '男';
3: 构造函数创建对象

// new 构造函数名();
        function Star(uname, age, sex) {
            this.name = uname;
            this.age = age;
            this.sex = sex;
            this.sing = function(sang) {
                console.log(sang);

            }
        }
        var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
        // console.log(typeof ldh);
        console.log(ldh.name);
        console.log(ldh['sex']);
        ldh.sing('冰雨');
        var zxy = new Star('张学友', 19, '男');
        console.log(zxy.name);
        console.log(zxy.age);
        zxy.sing('李香兰')
注意:

   // 1. 构造函数名字首字母要大写
        // 2. 我们构造函数不需要return 就可以返回结果
        // 3. 我们调用构造函数 必须使用 new
        // 4. 我们只要new Star() 调用函数就创建一个对象 ldh  {}
        // 5. 我们的属性和方法前面必须添加 this
View Code

 例2:浅谈构造函数和对象

// 构造函数和对象
        // 1. 构造函数  明星 泛指的某一大类  它类似于 java 语言里面的  类(class)
        function Star(uname, age, sex) {
            this.name = uname;
            this.age = age;
            this.sex = sex;
            this.sing = function(sang) {
                console.log(sang);

            }
        }
        // 2. 对象 特指 是一个具体的事物 刘德华 ==  {name: "刘德华", age: 18, sex: "男", sing: ƒ}
        var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
        console.log(ldh);
        // 3. 我们利用构造函数创建对象的过程我们也称为对象的实例化
View Code

 例3:new关键字的执行过程

// new关键字执行过程
        // 1. new 构造函数可以在内存中创建了一个空的对象 
        // 2. this 就会指向刚才创建的空对象
        // 3. 执行构造函数里面的代码 给这个空对象添加属性和方法
        // 4. 返回这个对象
        function Star(uname, age, sex) {
            this.name = uname;
            this.age = age;
            this.sex = sex;
            this.sing = function(sang) {
                console.log(sang);

            }
        }
        var ldh = new Star('刘德华', 18, '男');
View Code

js对象的注意点:

1. 对象是通过new操作符构建出来的,所以对象之间不想等(除了引用外);
2. 对象注意:引用类型(共同一个地址);
3. 对象的key都是字符串类型;
4. 对象如何找属性|方法;
    查找规则:先在对象本身找 ===> 构造函数中找 ===> 对象原型中找 ===> 构造函数原型中找 ===> 对象上一层原型查找

 例3:[1,2,3] ==[1,2,3]  // false      [1,2,3] ===[1,2,3]  // false

 例4:

var obj1 = {
    a:'hellow'
}
var obj2 = obj1;
obj2.a = 'world';
console.log(obj1);     //{a:world}
(function(){
    console.log(a);     //undefined
    var a = 1;
})();

注意: js中的数据类型包含 基本数据类型和引用数据类型。

  • 基本类型:string、number、boolean、undefined、null、symbol、bigint
  • 引用类型:object
  • NaN是一个数值类型,但是不是一个具体的数字
  • 基本数据类型:基本类型值在内存中占据固定大小,数据直接存储在栈内存中
  • 引用数据类型:引用类型在栈中存储了指针,这个指针指向堆内存中的地址,真实的数据存放在堆内存里。
  • 具体介绍看:https://blog.csdn.net/song_Web/article/details/126659522

 

例5:

var a = {}
var b = {
    key:'a'
}
var c = {
    key:'c'
}
 
a[b] = '123';
a[c] = '456';
 
console.log( a ); // {"[object Object]": "456"}
console.log( a[b] ); // 456

 四:JS作用域+this指向+原型的考题

 1:原型:每一个构造函数都有一个 prototype 属性,指向另一个对象。这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。

2:对象原型_proto_:对象身上系统自己添加一个 __proto__ 指向我们构造函数的原型对象 prototype

3:实例对象原型( __proto__)和构造函数原型对象(prototype)里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身

4: 原型链:每一个实例对象又有一个__proto__属性,指向的构造函数的原型对象,构造函数的原型对象也是一个对象,也有__proto__属性,这样一层一层往上找就形成了原型链。

5:对象成员的查找规则:当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有该属性。如果没有就查找它的原型(也就是 __proto__指向的 prototype 原型对象)。如果还没有就查找原型对象的原型(Object的原型对象)。依此类推一直找到 Object 为止(null),按照原型链的方式去查找。

6:原型对象的this指向:

  • 在构造函数中,里面this指向的是对象实例
  • 原型对象函数里面的this 指向的是 实例对象

例1:

function Foo(){
    getName = function(){console.log(1)} //注意是全局的window.
    return this;
}
 
Foo.getName = function(){console.log(2)}
Foo.prototype.getName = function(){console.log(3)}
var getName = function(){console.log(4)}
function getName(){
    console.log(5)
}
 
Foo.getName();    //2
getName();           //4
Foo().getName();  //1
getName();          //1
new Foo().getName();//3

例2:

var o = {
    a:10,
    b:{
        a:2,
        fn:function(){
            console.log( this.a ); // 2
            console.log( this );   //代表b对象
        }
    }
}
o.b.fn();

 

例3:

window.name = 'ByteDance';
function A(){
    this.name = 123;
}
A.prototype.getA = function(){
    console.log( this );
    return this.name + 1;
}
let a = new A();
let funcA = a.getA;
funcA();  //this代表window

例4:

var length = 10;
function fn(){
    return this.length + 1;
}
var obj = {
    length:5,
    test1:function(){
        return fn();
    }
}
obj.test2 = fn;
console.log( obj.test1() );                             //1
console.log( fn()===obj.test2() );                 //false
console.log( obj.test1() == obj.test2() ); //false

1. 原型可以解决什么问题

对象共享属性和共享方法
2. 谁有原型

函数拥有:prototype
对象拥有:__proto__
3. 对象查找属性或者方法的顺序

先在对象本身查找 --> 构造函数中查找 --> 对象的原型 --> 构造函数的原型中 --> 当前原型的原型中查找
4. 原型链
4.1 是什么?:就是把原型串联起来
4.2 原型链的最顶端是null

posted on 2023-03-15 18:39  paike123  阅读(109)  评论(4编辑  收藏  举报

导航