标签、订阅、继承、静态和实例方法、防抖节流、模块规范、require、异步方法、优雅退化和渐进增强

15 篇文章 0 订阅
4 篇文章 0 订阅

一、 b 和strong区别

同:用在网页上默认情况下起的均是加粗字体的作用。
不同:b标签是一个实体标签,字符将被设为bold(粗体),而strong标签是一个逻辑标签,标签语义化,它的作用是加强字符的语气,通过将字符加粗来实现。
盲人朋友使用阅读设备阅读网络时:strong会重读,b不会。
从网站优化方面分析,最主要的区别应该是strong标签内容比起b标签的内容更容易被抓取,也更容易使网站被用户搜索到。

I是Italic(斜体),而em是emphasize(强调)
strong标签和 em 标签一样,用于强调文本。

二、事件订阅和发布,怎样写一个事件中心

class Public {
    constructor() {
        this.handlers = {}
    }
    // 订阅事件
    on = function (eventType, handler) {
        if (!(eventType in this.handlers)) {
            this.handlers[eventType] = [];
        }
        this.handlers[eventType].push(handler);
        return this;
    }
    // 触发事件(发布事件)
    emit = function (eventType) {
        let handlerArgs = Array.prototype.slice.call(arguments, 1);
        if (this.handlers[eventType]) {
            for (let i = 0; i < this.handlers[eventType].length; i++) {
                this.handlers[eventType][i].apply(this, handlerArgs);
            }
        }
        return this;
    }
    // 删除订阅事件
    off = function (eventType, handler) {
        let currentEvent = this.handlers[eventType];
        let len = 0;
        // console.log(currentEvent)
        if (currentEvent) {
            len = currentEvent.length;
            // console.log(len)
            for (let i = len - 1; i >= 0; i--) {
                if (currentEvent[i] === handler) {
                    // console.log(currentEvent)
                    currentEvent.splice(i, 1);
                }
            }
            if (currentEvent.length == 0) {
                delete this.handlers[eventType]
            }
        }
        return this;
    }
}

// 测试代码
let Publisher = new Public();
let fn = (fn) => {
    console.log(fn)
}
let fn1 = (fn) => {
    console.log(fn,'哈哈哈哈哈')
}
// 订阅事件a
Publisher.on('a', fn);
Publisher.on('a', fn1);
// 触发事件a
Publisher.emit('a', '我是第1次调用的参数');
//取消事件a的绑定方法fn
Publisher.off('a', fn);
Publisher.emit('a', '我是第2次调用的参数'); 

三、关于继承可以怎样实现

ES6方式:用class关键字定义对象类型,用extends关键字实现继承,子类在构造方法中用super调用父类的构造方法。
prototype:添加属性、方法。

四、作用域类型 三种

全局作用域,函数作用域,块级作用域(es6的let、const)

五、object和function有什么区别或关联?

Object为函数,所以是Function的实例;Function.prototype为对象,所以是Object实例(因为原型对象就是一个对象)。所有的构造器都来自于Function.prototype,甚至包括根构造器Object及Function自身。

Function和Object,既是函数(因为都可以Function()或者Object()这样的方式执行),又是对象(因为可以Function.a = ‘a’,Object.a = 'a’这样赋值)。
说它们是函数,是因为他们都是通过”内置函数工厂“,派生出来的,因而具备函数的特性。说他们是对象,是因为他们都是通过”根源“对象,派生出来的,因此具备对象的特征。
Function.prototype指向”内置函数“。而Object.prototype指向”根源对象“。因而new Function会产生一个匿名函数,而new Object产生一个plain object(简单对象:通过字面量形式或者new Object()形式定义的对象)。
在这里插入图片描述

六、class实例方法和静态方法有什么区别?

在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。
1、调用静态方法示例。

//-----------hasStaticMethod.java-----------------
public class hasStaticMethod{
//定义一个静态方法
public static void callMe(){
  System.out.println("This is a static method.");
}
}

下面这个程序使用两种形式来调用静态方法。

//-----------invokeStaticMethod.java-----------------
public class invokeStaticMethod{
  public static void main(String args[]){
  hasStaticMethod.callMe(); //不创建对象,直接调用静态方法
  hasStaticMethod oa = new hasStaticMethod(); //创建一个对象
  oa.callMe(); //利用对象来调用静态方法
  }
}

2、静态方法访问成员变量示例。

//-----------accessMember.java-----------------
class accessMember{
private static int sa; //定义一个静态成员变量
private int ia; //定义一个实例成员变量
//下面定义一个静态方法
static void statMethod(){
  int i = 0; //正确,可以有自己的局部变量sa = 10;
  //正确,静态方法可以使用静态变量
  otherStat();
  //正确,可以调用静态方法
  ia = 20; //错误,不能使用实例变量
  insMethod(); //错误,不能调用实例方法
}
static void otherStat(){}
//下面定义一个实例方法
void insMethod(){
  int i = 0; //正确,可以有自己的局部变量
  sa = 15; //正确,可以使用静态变量
  ia = 30; //正确,可以使用实例变量
  statMethod(); //正确,可以调用静态方法
}
}

七、说说防抖节流有哪些区别

时间戳版和定时器版的节流函数的区别就是,时间戳版的函数触发是在时间段内开始的时候,而定时器版的函数触发是在时间段内结束的时候。

/**
 * @desc 函数防抖
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param immediate true 表立即执行,false 表非立即执行
 */
function debounce(func,wait,immediate) {
    var timeout;

    return function () {
        var context = this;
        var args = arguments;

        if (timeout) clearTimeout(timeout);
        if (immediate) {
            var callNow = !timeout;
            timeout = setTimeout(function(){
                timeout = null;
            }, wait)
            if (callNow) func.apply(context, args)
        }
        else {
            timeout = setTimeout(function(){
                func.apply(context, args)
            }, wait);
        }
    }
}

/**
 * @desc 函数节流
 * @param func 函数
 * @param wait 延迟执行毫秒数
 * @param type 1 表时间戳版,2 表定时器版
 */
function throttle(func, wait ,type) {
    if(type===1){
        var previous = 0;
    }else if(type===2){
        var timeout;
    }

    return function() {
        var context = this;
        var args = arguments;
        if(type===1){
            var now = Date.now();

            if (now - previous > wait) {
                func.apply(context, args);
                previous = now;
            }
        }else if(type===2){
            if (!timeout) {
                timeout = setTimeout(function() {
                    timeout = null;
                    func.apply(context, args)
                }, wait)
            }
        }

    }
}

八、AMD、CMD、CommonJs、ES6的对比

他们都是用于在模块化定义中使用的,AMD、CMD、CommonJs是ES5中提供的模块化编程的方案,import/export是ES6中定义新增的。

1)AMD-异步模块定义

AMD是RequireJS在推广过程中对模块定义的规范化产出,它是一个概念,RequireJS是对这个概念的实现,就好比JavaScript语言是对ECMAScript规范的实现。AMD是一个组织,RequireJS是在这个组织下自定义的一套脚本语言

RequireJS:是一个AMD框架,可以异步加载JS文件,按照模块加载方法,通过define()函数定义,第一个参数是一个数组,里面定义一些需要依赖的包,第二个参数是一个回调函数,通过变量来引用模块里面的方法,最后通过return来输出。

是一个依赖前置、异步定义的AMD框架(在参数里面引入js文件),在定义的同时如果需要用到别的模块,在最前面定义好即在参数数组里面进行引入,在回调里面加载

2)CMD
SeaJS在推广过程中对模块定义的规范化产出,是一个同步模块定义,是SeaJS的一个标准,SeaJS是CMD概念的一个实现,SeaJS是淘宝团队提供的一个模块开发的js框架.

通过define()定义,没有依赖前置,通过require加载jQuery插件,CMD是依赖就近,在什么地方使用到插件就在什么地方require该插件,即用即返,这是一个同步的概念

3)CommonJS规范
通过module.exports定义,在前端浏览器里面并不支持module.exports,通过node.js后端使用的。Nodejs端是使用CommonJS规范的,前端浏览器一般使用AMD、CMD、ES6等定义模块化开发的

输出方式有2种:默认输出—module export 和带有名字的输出—exports.area

4)ES6特性,模块化—export/import对模块进行导出导入

九、知道require吗?

ES6标准发布后,module成为标准,标准的使用是以export指令导出接口,以import引入模块,但是在我们一贯的node模块中,我们采用的是CommonJS规范,使用require引入模块,使用module.exports导出接口。

require和import的区别
区别1:模块加载的时间
require:运行时加载
import:编译时加载(效率更高)【由于是编译时加载,所以import命令会提升到整个模块的头部】
区别2:模块的本质
require:模块就是对象,输入时必须查找对象属性
import:ES6 模块不是对象,而是通过 export 命令显式指定输出的代码,再通过 import 命令输入(这也导致了没法引用 ES6 模块本身,因为它不是对象)。由于 ES6 模块是编译时加载,使得静态分析成为可能。

十、你知道哪些异步操作的方法

一、回调函数(callback)

回调是一个函数被作为一个参数传递到另一个函数里,在那个函数执行完后再执行。( 也即:B函数被作为参数传递到A函数里,在A函数执行完后再执行B )

假定有两个函数f1和f2,后者等待前者的执行结果。
f1();
f2();
如果f1是一个很耗时的任务,可以考虑改写f1,把f2写成f1的回调函数。

异步回调:

function f1(callback){
  setTimeout(function () {
    // f1的任务代码
    callback();
  }, 1000);
}
// 执行
f1(f2)

采用这种方式,我们把同步操作变成了异步操作,f1不会堵塞程序运行,相当于先执行程序的主要逻辑,将耗时的操作推迟执行。

回调函数是异步编程最基本的方法,其优点是简单、容易理解和部署,缺点是不利于代码的阅读和维护,各个部分之间高度耦合(Coupling),流程会很混乱,而且每个任务只能指定一个回调函数。

注意 区分 回调函数和异步,回调并不一定就是异步。他们自己并没有直接关系。

同步回调 :

function A(callback){
    console.log("I am A");
    callback();  //调用该函数
}
function B(){
   console.log("I am B");
}
A(B);

二、事件监听
采用事件驱动模式。
任务的执行不取决代码的顺序,而取决于某一个事件是否发生。

监听函数有:on,bind,listen,addEventListener,observe

还是以f1和f2为例。首先,为f1绑定一个事件(采用jquery写法)。

f1.on('done',f2);

上面代码意思是,当f1发生done事件,就执行f2。

然后对f1进行改写:

function f1(){
    settimeout(function(){
       //f1的任务代码
       f1.trigger('done');  
    },1000);
}

f1.trigger(‘done’)表示,执行完成后,立即触发done事件,从而开始执行f2.

优点:比较容易理解,可以绑定多个事件,每一个事件可以指定多个回调函数,而且可以去耦合,有利于实现模块化。
缺点:整个程序都要变成事件驱动型,运行流程会变得不清晰。
三、发布/订阅
我们假定,存在一个"信号中心",某个任务执行完成,就向信号中心"发布"(publish)一个信号,其他任务可以向信号中心"订阅"(subscribe)这个信号,从而知道什么时候自己可以开始执行。这就叫做"发布/订阅模式"(publish-subscribe pattern),又称"观察者模式"(observer pattern)。

首先,f2向"信号中心"jQuery订阅"done"信号。

jQuery.subscribe("done", f2);

然后,f1进行如下改写:

function f1(){
  setTimeout(function () {
    // f1的任务代码
    jQuery.publish("done");
  }, 1000);
}

jQuery.publish(“done”)的意思是,f1执行完成后,向"信号中心"jQuery发布"done"信号,从而引发f2的执行。
f2完成执行后,也可以取消订阅(unsubscribe)。

jQuery.unsubscribe("done", f2);

这种方法的性质与"事件监听"类似,但是明显优于后者。因为我们可以通过查看"消息中心",了解存在多少信号、每个信号有多少订阅者,从而监控程序的运行。
四、promise对象(promise 模式)
(1)promise对象是commonJS工作组提出的一种规范,一种模式,目的是为了异步编程提供统一接口。
(2)promise是一种模式,promise可以帮忙管理异步方式返回的代码。他讲代码进行封装并添加一个类似于事件处理的管理层。我们可以使用promise来注册代码,这些代码会在在promise成功或者失败后运行。
(3)promise完成之后,对应的代码也会执行。我们可以注册任意数量的函数再成功或者失败后运行,也可以在任何时候注册事件处理程序。
(4)promise有两种状态:1、等待(pending);2、完成(settled)。promise会一直处于等待状态,直到它所包装的异步调用返回/超时/结束。
(5)这时候promise状态变成完成。完成状态分成两类:1、解决(resolved);2、拒绝(rejected)。
(6)promise解决(resolved):意味着顺利结束。promise拒绝(rejected)意味着没有顺利结束。

//promise
var p=new Promise(function(resolved))
//在这里进行处理。也许可以使用ajax
setTimeout(function(){
   var result=10*5;
   if(result===50){
      resolve(50);
   }else{
     reject(new Error('Bad Math'));
  }
},1000);
});
p.then(function(result){
    console.log('Resolve with a values of %d',result);
});
p.catch(function(){
   console.error('Something went wrong');
});

(1)代码的 关键在于setTimeout()的调用。

(2)重要的是,他调用了函数resolve()和reject()。resolve()函数告诉promise用户promise已解决;reject()函数告诉promise用户promise未能顺利完成。

(3)另外还有一些使用了promise代码。注意then和catch用法,可以将他们想象成onsucess和onfailure事件的处理程序。

(4)巧妙地方是,我们将promise处理与状态分离。也就是说,我们可以调用p.then(或者p.catch)多少次都可以,不管promise是什么状态。

(5)promise是ECMAscript 6管理异步代码的标准方式,javascript库使用promise管理ajax,动画,和其他典型的异步交互。
五、优雅的async/await

十一、你知道页面优雅退化和渐进增强吗?

(1)平稳退化(优雅降级)

使用最新的技术面向高级浏览器构建最强的功能及用户体验,然后针对低级的浏览器进行限制,逐步衰减那些无法被支持的功能及体验。首先完整的实现了网站,其中包括所有的功能和特效。 然后再为那些无法支持所有功能的浏览器增加候选方案,使之在旧市的浏览器上可以以某种形式降级体验却不至于完全失效。
例子:首先针对Firefox或者Chrome等支持W3C标准的浏览器编写页面代码,然后修复IE中的异常或针对IE去除那些无法被实现的功能特色。

(2)渐进增强

从最基本的可用性出发,在保证站点页面在低级浏览器中的可用性和可访问性的基础上,逐步增强功能及提高用户体验。渐进增强方案并不假定所有的用户都支持javascript,而总是提供一种候补方法,确保用户可以访问(主要的)内容。
例如:首先使用标记语言编写页面,然后通过样式表来控制页面样式;使用HTML5、CSS3等新技术,针对高级浏览器为页面提高用户体验。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值