前端知识回顾

本文探讨了JavaScript的面向对象特性、??与||的区别,并详细介绍了前端图片优化策略,包括懒加载、CSSprite等。同时,讲解了CSS硬件加速、重绘与回流的原理以及如何减少它们的影响。此外,深入解析了闭包的概念,事件句柄和事件源的定义,以及异步编程的多种方式,如回调函数、Promise和async/await。最后,简述了ES6的class和继承机制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

总结网址:前端导航

GitHub - sindresorhus/awesome: 😎 Awesome lists about all kinds of interesting topics

1.js是面向对象还是基于对象?

面向对象的三大特点:封装,继承,多态。

面向对象:先有一个抽象的类,然后根据这个类去实例化对象。

eg:java实例化对象

public class A{

    private String name ;

    private int age;

    public void A(String name,int age){
        this.super();

        this.name = name;
        this.age = age

    }
    public String getName(){

        return this.name;
    }
    public void setName(String name){
        this.name = name
    }        

}

//对象实例化
A objA = new A("DaMing",18);

eg:js实例化对象

//点击按钮,改变div的样式--面向对象(高级)
//ChangeStyle是构造函数
function ChangeStyle(btnObj,divObj,json){
    this.btnObj=btnObj;
    this.divObj=divObj;
    this.json = json;
}
ChangeStyle.prototype.init = function() {
    //点击按钮改变div样式
    var that = this;    // 此处必须转存this,因为在function中this表示该点击事件的对象
    this.btnObj.onclick=function() {
        for(var key in that.json){
            that.divObj.style[key]=that.json[key];
        }
    }
}
//实例化对象
var btnObj=document.getElementById("btnId");
var divObj=document.getElementById("divId");
var json = {"width": "500px","height": "500px","backgroundColor": "green","opacity": "0.1",}
var test = new ChangeStyle(btnObj, divObj, json);
test.init();//调用方法

基于对象:现有一个具体的类再去实例化对象。基于对象是没有继承的说法

2.JavaScript 中 ?? 与 || 的区别

??用法:   表达式1  ??  表达式2

如果表达式1为undefin或null时返回表达式2

   || 用法     表达式1  ||  表达式2

如果表达式1为false返回表达式2

??更加适合在不知道变量是否有值时使用。

 3.前端支持图片:

  • png-8png-24jpeggifsvg
  • WebpWebP格式,谷歌(google)开发的一种旨在加快图片加载速度的图片格式。图片压缩体积大约只有JPEG2/3,并能节省大量的服务器带宽资源和数据空间。Facebook Ebay等知名网站已经开始测试并使用WebP格式。
  • 在质量相同的情况下,WebP格式图像的体积要比JPEG格式图像小40%
  • Apng:全称是“Animated Portable Network Graphics”, 是PNG的位图动画扩展,可以实现png格式的动态图片效果。04年诞生,但一直得不到各大浏览器厂商的支持,直到日前得到 iOS safari 8的支持,有望代替GIF成为下一代动态图标准

4.一个页面上有大量的图片(大型电商网站),加载很慢,你有哪些方法优化这些图片的加载,给用户更好的体验。

  • 图片懒加载,在页面上的未可视区域可以添加一个滚动事件,判断图片位置与浏览器顶端的距离与页面的距离,如果前者小于后者,优先加载。
  • 如果为幻灯片、相册等,可以使用图片预加载技术,将当前展示图片的前一张和后一张优先下载。
  • 如果图片为css图片,可以使用CSSspriteSVGspriteIconfontBase64等技术。
  • 如果图片过大,可以使用特殊编码的图片,加载时会先加载一张压缩的特别厉害的缩略图,以提高用户体验。
  • 如果图片展示区域小于图片的真实大小,则因在服务器端根据业务需要先行进行图片压缩,图片压缩后大小与展示一致。
  • 图片裁剪

5.如何使用CSS实现硬件加速?

硬件加速是指通过创建独立的复合图层,让GPU来渲染这个图层,从而提高性能,

  • 一般触发硬件加速的CSS属性有transformopacityfilter,为了避免2D动画在 开始和结束的时候的repaint操作,一般使用tranform:translateZ(0)

6. 重绘和回流(重排)是什么,如何避免?

  • 重绘:当渲染树中的元素外观(如:颜色)发生改变,不影响布局时,产生重绘
  • 回流:当渲染树中的元素的布局(如:尺寸、位置、隐藏/状态状态)发生改变时,产生重绘回流
  • 注意:JS获取Layout属性值(如:offsetLeftscrollTopgetComputedStyle等)也会引起回流。因为浏览器需要通过回流计算最新值
  • 回流必将引起重绘,而重绘不一定会引起回流

7.如何最小化重绘(repaint)和回流(reflow)

  • 需要要对元素进行复杂的操作时,可以先隐藏(display:"none"),操作完成后再显示
  • 需要创建多个DOM节点时,使用DocumentFragment创建完后一次性的加入document
  • 缓存Layout属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
  • 尽量避免用table布局(table元素一旦触发回流就会导致table里所有的其它元素回流)
  • 避免使用css表达式(expression),因为每次调用都会重新计算值(包括加载页面)
  • 尽量使用 css 属性简写,如:用 border 代替 border-widthborder-styleborder-color
  • 批量修改元素样式:elem.className 和 elem.style.cssText 代替 elem.style.xxx

8.如何理解闭包?

1.定义:

官方定义:是指拥有多个变量和绑定了这些变量的环境的 表达式(通常是一个函数),因而这些变量也是该表达式 的一部分。

通俗来说就是在函数内部定义函数,内部的函数可以拿到外部函数的变量。

2.用途:

用于读取函数内部变量,以及一直把变量保持在内存中

变量一直存在在内存中是因为内部函数引用了外部函数的变量,变量得不到释放,就会一直存在在内存中。这也会引起另一个问题就是内存泄漏,所以记得在变量不用时记得设为null。

9.事件句柄和事件源:

事件句柄:发生事件时要执行的操作。

事件源:产生事件的标签或元素。

10.js异步编程

  •  回调函数

         将函数作为参数传递到另一个函数中去执行

        官方定义: A callback is a function that is passed as an argument to another function and is executed after its parent function has completed.

例子:

$("#dom").click(function(){

        alert("事件回调")

});

优点:

        简单、容易理解

        解决了同步的问题(只要有一个任务耗时很长,后面的任务都必须排队等着, 会拖延整个程序的执行。

 缺点:

        易形成回调地狱

        不能用try...catch捕获错误

        不能return

        不利于维护,代码耦合高

  • promise

Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Resolved(已完成,又称 Fulfilled)和 Rejected(已失败)。

promise是ES6支持的新语法在较低的浏览器版本是不支持的。promise有三个方法then(),

catch(),finally(),其中then方法可多次调用,finally执行与代码位置有关,catch和finally也可多次使用,但是catch无异常时只会调用一次,建议catch和finally只使用一次

用法:

var promise = new Promise(function(resolve,reject){

}).then(function(){

}).catch(function(){

}).finally(function(){

})

promise的两个方法:

Promise.all(arr);接受一个由promise构成的数组,异步执行后将返回结果合成一个数组返回一个promise.race(arr):接受一个由promise构成的数组,哪个promise执行的快以谁的数据执行回调resolve();

promise优点:

      解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。

     Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和手法。

        链式处理,写法更加清晰

        加入了错误处理方法catch()

promise缺点:

        不能中途取消promise,一旦新建就会立即执行

        当promise未执行完好处于pending状态时,不能知道处于什么状态

手写promise:简单版

        var PENDING = 'pending';
        var FULFILED = "fulfilled";
        var REJECTED = "rejected";
        function MyPromise(fn){
            this.status = PENDING;//初始状态
            this.value= null;//初始化resolved参数
            this.reason = null;//初始化rejected参数

            // 构造函数里面添加两个数组存储成功和失败的回调
            this.onFulfilledCallbacks = [];
            this.onRejectedCallbacks = [];
            var that = this;
            var resolved = function(value){
                if(that.status==PENDING){
                    that.value = value;
                    that.status=FULFILED;
                    that.onFulfilledCallbacks.forEach(callback=>{
                        if(typeof callback  == 'function'){
                            callback(value)
                        }
                        
                    })


                }
            }
            var rejected = function(reason){
                if(that.status==PENDING){
                    that.value = value;
                    that.status=REJECTED;
                    that.onRejectedCallbacks.forEach(callback=>{
                        if(typeof callback  == 'function'){
                            callback(reason);
                        }
                        
                    })

                }
            }
            try {
                fn(resolved, rejected);
            } catch (error) {
                rejected(error);
            }

        }
        
        MyPromise.prototype.then = function(resolve,reject){
            if(this.status == PENDING){
                this.onFulfilledCallbacks.push(resolve);
                this.onRejectedCallbacks.push(reject);
            }else if(this.status == FULFILED){
                resolve(this.value);
            }else{
                reject(this.reason);
            }
            return this;
        }
        const p = new MyPromise((resolve, reject) => {
        setTimeout(() => {
            resolve(1000);
        }, 2000);
        });

        p.then((res) => {
        console.log('结果:', res); // 结果:1000
        }).then(() => {
        console.log('执行完成'); 
        })

  • async/await

async是用来修饰函数的,放在函数前就表示这是一个异步函数,会返回一个promise对象

async function fn(){
    return 1;
}

await 关键字只能放到async 函数里面

面试题1:

// 说出下面代码的输出
        async function async1() {
            console.log('async1 start');
            await async2();
            console.log('async1 end');
        }
        async function async2() {
            console.log('async2');
        }

        console.log('script start');
        setTimeout(() => {
            console.log('setTimeout');
        }, 0);
        async1();
        new Promise(function (resolve) {
            console.log('promise1');
            resolve();
        }).then(function () {
            console.log('promise2');
        });
        console.log('script end');


       答案:
        /**
         * script start
         * async1 start
         * async2
         * promise1
         * script end'
         * async1 end
         * promise2
         * setTimeout
         * 
         * /

面试题变体:

async function async1() {
            console.log('async1 start');
            await async2();                
            console.log('async1 end');//微任务1 2
        }
        async function async2() {
            await async3(); 
            console.log('async2');//微任务1 1
        }

        async function async3() {
            await async4();
            console.log('async3');//微任务1
        }
        async function async4() {
            console.log('async4');
        }

        console.log('script start');
        setTimeout(function() {
            console.log('setTimeout');//宏任务1
        }, 0)
        async1();
        new Promise(function(resolve) {
            console.log('promise1');
            resolve();
        }).then(function() {
            console.log('promise2');//微任务2
        });
        console.log('script end');
         /**
          * script start
            async1 start
            async4
            promise1
            script end
            async3
            promise2
            async2
            async1 end
            setTimeout
          * ***/

改写async/await为promise

async function async1() {
            console.log('async1 start');
            await async2();
            console.log('async1 end');
        }
        async function async2() {
            console.log('async2');
        }

new Promise(function(resolve,reject){
    console.log('async1 start');
    console.log('async2');
    resolve();
    
}).then(function(){
    
    console.log('async1 end');
})
  • jquery的deferred对象

deferred对象是一个延迟对象,意思是函数延迟到某个点才开始执行,改变执行状态的方法有两个(成功:resolve和失败:reject),分别对应两种执行回调(成功回调函数:done和失败回调函数fail)

eg:

var wait=function(){
    var tasks=function(){
        console.log("执行完毕!");
    };
    setTimeout(tasks,5000);
};
$.when(wait())
.done(function(){console.log("success");})
.fail(function(){console.log("error")});

结果:

success

执行完毕!

var dtd=$.Deferred();
var wait=function(dtd){
var tasks=function(){
console.log("执行完毕!");
dtd.resolve();
};
setTimeout(tasks,5000);
return dtd;
};
$.when(wait(dtd))
.done(function(){console.log("success");})
.fail(function(){console.log("error")});

结果:

执行完毕!
 success

11.es6的class

语法:

let MyClass = class{

        constructor(a){

                this.a = a;

         }

}

let MyClass = class MyClass{

        constructor(a){

                this.a = a;

        }

}

es5与es6写法对比

function MyClass(x,y){
            this.x = x;
            this.y = y;
            console.log(this.x,this.y)
        }
        MyClass.prototype.name="MyClass";
        MyClass.prototype.add = function(a,b){
            console.log("a+b=",a+b);
            return a+b;
        }

       var myclass = new MyClass(1,2);
       myclass.add(5,5);
       console.log(MyClass);
       console.log(myclass);

       console.log("=========================这是一条分割线=======================================")  


       class MyClass1{
            constructor(x,y){
                this.x = x;
                this.y = y;
                console.log(x,y)
            }
            add(a,b){
                console.log("a+b=",a+b);
                return a+b;
            }

       }
       var myclass1 = new MyClass1(1,2);
       myclass1.add(5,5);
       console.log(MyClass1);
       console.log(myclass1);

类上新增方法:

Object.assign(MyClass.prototype, { hello(){} });

类的定义不会被提升,类的方法也不需要function关键字,方法间不能加分号,

name属性

类名.name返回类名

constructor方法:默认方法,创建类的实例化对象被调用

this指向:指向该类的实例

静态方法:

class MyClass{

        static add(x,y){

                return (x+y);

         }

}

原型方法:

class MyClass{

         add(x,y){

                return (x+y);

         }

}

实例方法:

class MyClass{

        constructor(){

              add(x,y){

                    return (x+y);

              }

        }

}

类的实例:   new MyClass();

类的getter和setter方法(这里取值和赋值需要前面添加下划线否则会不断递归报错RangeError)

class MyClass1{
            constructor(x,y){
                this.x = x;
                this.y = y;
                console.log(x,y)
            }
            get x(){
                console.log("get");
                return this._x;
            }
            set x(x){
                console.log('set')
                this._x  = x;
            }
            add(a,b){
                console.log("a+b=",a+b);
                return a+b;
            }


       }

类的继承:(extends)

super:子类 constructor 方法中必须有 super ,且必须出现在 this 之前。

调用父类方法, super 作为对象,在普通方法中,指向父类的原型对象,在静态方法中,指向父类

 class MyClass1{
            constructor(x,y){
                this.x = x;
                this.y = y;
                console.log(x,y)
            }
            get x(){
                console.log("get");
                return this._x;
            }
            set x(x){
                console.log('set')
                this._x  = x;
            }
            add(a,b){
                console.log("a+b=",a+b);
                return a+b;
            }
            static hello(){
                return "hello";
            }
       }
       class Son extends MyClass1{
           constructor(x,y){
                super(x,y)
           }
           minus(a,b){
                console.log("a-b=",a-b)
                return a-b;
           }
           static hello(){
               console.log(super.hello()+this.name)
           }
       }
       var myclass1 = new MyClass1(1,2);
       var son = new Son(9,9);
       console.log(son);
       son.add(0,1);
       son.minus(1,1)
       Son.hello();

decorator:装饰器

简单来说就是对目标类进行修改操作,这个操作是在编译时发生的

装饰器只能用于类和类的方法,不能用于函数,因为存在函数提升

function testable(isTestable) {
  return function(target) {
    target.isTestable = isTestable;
  }
}

@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true

@testable(false)
class MyClass {}
MyClass.isTestable // false

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值