前端面试问题(适用于面试回答思路)

本文详细探讨了前端面试中的核心知识点,涵盖箭头函数、普通函数与构造函数的差异,以及this绑定、原型链、JavaScript继承方式。还讨论了匿名函数、new操作符的工作原理,深入剖析了作用域、作用域链、执行上下文和事件循环机制。此外,文章还涉及了闭包、私有变量、JS执行机制、异步操作、数据类型判断、数组方法、DOM操作和前端安全等多个主题,全面解析了前端开发者应掌握的重要概念和技术。
摘要由CSDN通过智能技术生成

箭头函数、普通函数、构造函数

js构造函数详解
js中箭头函数和普通函数的区别
箭头函数特点:
1)箭头函数内部的this对象,就是函数上下文中的对象,而不是调用时的对象,不能用call,appply等方法改变this指向。
2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
3)不可以使用arguments对象,该对象在函数体内不存在,如果要用,可以用rest参数代替。
4)不可以使用yield命令,因此箭头函数不能用作Generator函数。

箭头函数用法:
1)使回调函数更简洁
2)搭配数组方法使用
不能使用的场景:需要用到函数方法中this的情况,不可作为构造函数使用

箭头函数没有函数名,不可以像普通函数一样作为构造函数使用,也不能用new创建实例类型。原因在于箭头函数中的this是固定的,在普通函数中this指向调用它的对象,而在箭头函数中,this永远指向其上下文。它的固定不是因为this绑定,是在于因为箭头函数没有自己的this,导致内部代码块的this就是外层代码块的this。因此箭头函数不能作为构造函数。箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()

构造函数通过“new 函数名”来实例化函数,任何的普通函数都可以作为构造函数使用,它们主要是从功能上来区分的。普通函数作为可以复用的代码,构造函数主要用来创建实例对象,特点是和new一起使用。在实践中通常使用首字母大写来区分。class 为构造函数的语法糖,即 class 的本质是构造函数,在执行时会转换为构造函数执行。

匿名函数

匿名函数是一个function关键字后没有标识符的函数表达式。通过匿名函数可以实现闭包。匿名函数模拟了块级作用域,执行完匿名函数后,存储在内存中的相应变量会被销毁。使用匿名函数可以减少全局变量,降低命名冲突。
缺点:调试困难,降低代码可读性。

this对象是在运行时基于函数执行环境绑定的,在全局函数中,this=window,在函数被作为某个对象的方法调用时,this等于这个对象。

匿名函数立即执行,也称为立即执行函数表达式(IIFE)

    // 无参数的匿名函数
    (function () {
   
        console.log('zxx')
    })();
    
    // 推荐使用
    (function () {
   
        console.log('zxx')
    }())
 
    // 带参数的匿名函数
    (function (a, b, c) {
   
        console.log('参数一:', a) // 参数一: 这是普通函数传参的地方
        console.log('参数二:', b) // 参数二: 我是参数二
        console.log('参数三:', c) // 参数三: zxx
    })('这是普通函数传参的地方', '我是参数二', 'zxx')
    
    //匿名函数赋值
    let zxx = function (zxx) {
   
        console.log(zxx)
    }('zxx')

匿名函数用法

    1.事件
    $('#zxx').onclick = function () {
   
        console.log('给按钮添加点击事件')
    }
 
    2.对象
    var obj = {
   
        name: 'zxx',
        zxx: function () {
   
            return this.name + ' is' + ' good girl'
        }
    }
    console.log(obj.zxx()) // zxx is good girl
    
    3.函数表达式
    var zxx = function () {
   
        return 'zxx is good girl'
    }
    console.log(zxx()) // zxx is good girl
 
    4.回调函数
    setInterval(function () {
   
        console.log('zxx is good girl')
    }, 1000)
 
    5.作为函数的返回值
    function zxx () {
   
        // 返回匿名函数
        return function () {
   
            return 'zxx'
        }
    }
    console.log(zxx()()) // zxx

new实现了什么

1、首先创一个新的空对象。
2、根据原型链,设置空对象的 _proto_为构造函数的 prototype ,并将this指向新创建的对象。
3、执行构造函数的代码(为这个新对象添加属性)。
4、返回这个对象。
对new理解:new 申请内存, 创建对象,当调用new时,后台会隐式执行new Object()创建对象。所以,通过new创建的字符串、数字是引用类型,而是非值类型。
new 被调用后大致做了哪几件事情?
📒 让实例可以访问到私有属性;
📒 让实例可以访问构造函数原型(constructor.prototype)所在原型链上的属性;
📒 构造函数返回的最后结果是引用数据类型。

原型和原型链

为了将所有的对象关联起来,引入了prototype函数对象来包含所有实例对象的构造函数的属性和方法,引入了proto和原型链的概念解决继承的问题。
原型:构造函数的 prototype 属性指向了一个对象,它是调用该构造函数而创建的实例的原型,也就是原型对象,由实例对象的内置属性_proto_指向。每个原型都有一个 constructor 属性指向关联的构造函数。
原型用法:构造函数创建的实例可以访问实例的属性和方法,也可以访问原型的属性和方法。原型可以让所有实例对象共享原型包含的方法和属性,利用这个特性我们可以提取对象的公共属性和方法放在原型中。
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。
原型链:子类构造函数的prototype的__proto__指向父类构造器的prototype,通过_proto_将原型对象链接起来。原型链是多个原型的关联,本质是一串顺序指向原型对象的指针列表。
原型链用法:当实例对象访问某个属性或方法时,首先会在自己的属性里查找,找不到就会沿着_proto_指针向上查找原型对象中的属性和方法。
问题:1、由于原型的属性和方法变成实例对象的共有属性和方法,因此对原型对象属性的修改会引起其他实例的变化。2、如果重写原型对象,相当于构造函数指定了新的原型对象,而已创建的实例的_proto_仍指向旧的原型,访问不到新原型的方法。

function SuperType(){
   
    this.colors = ["red", "blue", "green"];
}
SuperType.prototype.Fun = function(){
   
 
};
function SubType(){
   
}
//继承了SuperType
SubType.prototype = new SuperType();
var instance1 = new SubType();
instance1.colors.push("black");
alert(instance1.colors); //"red,blue,green,black"
var instance2 = new SubType();
alert(instance2.colors); //"red,blue,green,black"

在这里插入图片描述

JS中的继承

一篇文章理解JS继承
原型链继承、构造函数继承、组合继承、原型式继承、寄生继承、寄生组合继承。ES6中新增extends继承方法。
原型链继承,将父类的实例作为子类的原型。会共享引用属性。
构造函数继承,将父类构造函数的内容复制给了子类的构造函数。会独享所有属性,包括引用属性(重点是函数)。
组合继承,利用原型链继承要共享的属性,利用构造函数继承要独享的属性,实现相对完美的继承。
原型链继承与构造函数继承恰好相反,结合使用弥补缺点,用构造函数继承属性,用原型链继承函数,形成组合继承。
原型式继承,与原型链继承优缺点相同,本质是对象的浅复制。没有方法复用。
寄生组合继承:通过借用构造函数来继承属性,通过原型链形式来继承方法,复制父类构造函数的原型作为子类的原型,解决2次调用父类函数以及复用率的问题,是一种理想的继承方法。
ES6继承的结果和寄生组合继承相似,本质上,ES6继承是一种语法糖。使用Object.setPrototypeOf()。
class 为 构造函数的语法糖,即 class 的本质是 构造函数。class的继承 extends 本质 为构造函数的原型链的继承。
两者不同点
ES6有子类到父类的原型链指向,而ES5中是构造函数复制,没有原型链指向。
ES6中子类实例基于父类实例构建,ES5不是。
在这里插入图片描述

静态方法、实例方法、原型方法

静态方法:静态方法属于类,实例对象不能调用。类的静态方法只能访问静态属性。
使用上:直接在类(构造函数)上定义,或通过static关键字在类(构造函数)内部定义。
实例方法:实例方法属于对象,只有在创建了实例的情况下才可以通过实例访问。
使用上:在类(构造函数)的实例上定义,在构造函数中通过this指针定义。
原型方法:实例和构造函数(通过prototype)都可以调用,是共享的方法。
使用上:通过类的prototype定义。
实例对象不能调用静态方法,类不能调用实例方法。
使用实例方法的目的是为了更好的面向对象。

//创建一个类(构造函数,构造函数是定义类的一个方法)
var Person=function(){
   
    console.log("person");
}
//创建这个类(构造函数)的静态方法
Person.say=function (){
   
    console.log("aaaaa");
}
Person.say();//aaaaa
//创建这个类(构造函数)的对象实例
var zym=new Person();
console.log(zym);//Person {}
//创建实例方法
zym.sayMe=function (){
   
    console.log("zym");
}
zym.sayMe();//zym
zym.say();//报错,实例方法无法访问静态方法

//使用class和static关键字的静态方法
class Person2{
   
    static say(){
   
        console.log("person2");
    }
}
var zym2=new Person2();
console.log(zym2);//Person2 {}
Person2.say();//person2

//使用prototype实现原型方法
Person2.prototype.sayAge=function (age){
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值