JavaScript 简单原理题

1.JS中的数据类型和常用的判断数据类型的方法

基本数据类型
String  字符串  Number  数字  null  空  Boolean  布耳值  undefined  未定义的  symbol 唯一值  bigInt 大数字
引用数据类型
Object  对象  Array  数组  Date  时间  Function  函数  RegExp  正则

2.let var const的区别

用var声明的变量,存在变量的提升。
用let/const声明的变量,不存在变量的提升。
变量提升:变量在声明之前可以使用,并且代码不报错(预解析)。
用var声明的变量,允许重复声明。
用let/const声明的变量,不允许重复声明。
用var声明的变量,不存在块级作用域。
用let/const声明的变量,存在块级作用域。

3.js中的this指向

方法中谁调用,this就指向谁。(.前面是谁,this就指向谁)
如果没有人调用的时候this默认指向window。
构造函数中的this,指向通过这个构造函数创建出来的实例本身。
强制改变this指向:call/apply/bind。
call方法和apply方法声明后会直接调用。call跟的是一个参数集合,用逗号分割。apply跟的是一个数组。
bind不会直接的调用,需要用()(),的方法调用。bind本身不会去执行要被改变this指向的这个方法。而是会返回一个已经改变this指向的新方法。

4.箭头函数与普通函数的区别

箭头函数的this,始终指向父级的上下文。
箭头函数是一个匿名函数,不能作为构造函数使用,不能使用new。
箭头函数没有原型属性。
箭头函数内没有arguments,可以用展开运算符...解决。
arguments是一参数的集合、是一个伪数组。当不确定有几个参数的时候,用arguments来接收。
伪数组转数组  Array.from() /  Array.prototype.slice.call()。

5.数组常用方法(至少6个详细说明)

forEach() 数组循环、遍历 --> 原生js
every()法用于检测数组所有元素是否都符合指定条件。
(es6)every遍历数组每一项,每一项返回true, 则最终结果为true,
当任何一项返回false时,停止遍历,返回false。不改变原数组 不改变原数组的值。
concat()方法用于连接两个或多个数组或字符串。
pop()删除并返回数组的最后一个(删除元素) 改变原数组。
push()末尾添加元素, 返回新的长度 改变原数组。
shift()把数组的第一个元素删除,并返回第一个元素的值 改变原数组。
unshift()将参数添加到原数组开头,并返回数组的长度。
findIndex()获取元素在数组的索引下标。

6.原型和原型链

原型
每一个函数都有一个prototype,被称为显示原型,函数的实例对象有一个__proto__属性,被称为隐式原型。隐式原型__proto__指向构造函数的显示
原形prototype。每一个prototype显示原型都有一个constructor属性,指向其关联的的构造函数。

原型链
获取对象的属性的时候,如果本身没有这个属性,就会去其原型__proto__上找,如果还查找不到,就去找原型的原型,直到找到最顶层的Object.prototype,
Object.prototype也有__proto__属性,属性值为null。这种层层寻找的机制就叫原型链。

7.作用域和闭包

作用域
全局作用域、函数(局部)作用域、块级作用域
函数作用域 --> 函数在执行的时候会产生一个独立的作用域。
块级作用域 ES新增的 --> {} 每一个{}就是一个块级作用域。

闭包
函数内部返回一个新的函数

  function fn1(){
var a = 1;
return function () {
    console.log(a);
  }
}

闭包的有优缺点

优点
1.变量长期驻扎在内存中。
2.可以重复使用变量,并且不会造成变量的污染。

缺点

由于闭包会使得函数中的变量都被保存在内存中,内存消耗大,不能滥用闭包,否则会影响页面的性能。在IE中会导致内存的泄露。解决的方案是在退出函数
之前,将不使用的局部变量全部删除。

8.谈一下你理解的面向对象

面向对象和面向过程一样,都是一种编程思想(万物皆对象)。
JS本身也是一门面向对象的语言,js和vue都是基于面向对象的编程思想构造出来的。
S中的面向对象和后端语言常见的面向对象稍微有些不同,JS中的类和实例是基于原型和原型链机制来处理的。
封装:高内聚低耦合。
继承:子类 实例 继承父类的属性和方法。
重写:修改已有的属性和方法。
重载 JS本身是没有重载的,重载对于客户端代码来说是没有必要的。

9.声明一个父类和一个子类,并且实现子类继承父类

//父类的构造函数
    function Parent(x) {
        this.x = x;
        this.sayHello = function () {
            console.log('sayHello')
        }
    }

    // 父类原型
    Parent.prototype.getX = function () {
        console.log('getX', this.x)
    }
    let p1 = new Parent(100)

    //子类构造函数
    function Child(y) {
        Parent.call(this, 666) //让父类的构造函数的this指向子类构造函数
        this.y = y;
    }

    Child.prototype = Object.create(Parent.prototype);
    Child.prototype.constructor = Child;
    Child.prototype.getY = function () {
        console.log('getY', this.y)
    }
    //子类实例
    let c1 = new Child(200, 666);

10.什么是深拷贝和浅拷贝,使用递归的方式实现一个深拷贝

深拷贝和浅拷贝是针对与引用数据类型,进行数据拷贝。在不影响原数据的情况下,再复制一份数据出来。
let obj = {
        a: 1,
        b: 2,
        c: {
            name: "哈哈",
            age: 18,
            friend: [
                {
                    name: "嘻嘻",
                    age: 16,
                },
            ]
        },
        d: [1, 2, 3, 4]
    }
    // 浅拷贝:对于复杂综合的数据,只拷贝第一层
    let obj2 = {};
    for (let Key in obj) {
        obj2[Key] = obj[Key]
    }

    // 深拷贝:层层拷贝
    function deepCopy(obj) {
        let result = Array.isArray(obj) ? [] : {};
        for (let key in obj) {
            if (obj.hasOwnProperty(key)) {
                if (typeof obj[key] === 'object' && obj[key] !== null) {
                    result[key] = deepCopy(obj[key])
                } else {
                    result[key] = obj[key]
                }
            }
        }
        return result
    }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值