同:用在网页上默认情况下起的均是加粗字体的作用。
不同: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的实例;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()形式定义的对象)。
在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。
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是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对模块进行导出导入
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等新技术,针对高级浏览器为页面提高用户体验。