JavaScript——杂项

@

JavaScript语言特点

  1. 脚本语言。JavaScript 是一种解释型的脚本语言,C、C++等语言先编译后执行,而 JavaScript 是在程序的运行过程中逐行进行解释。

  2. 基于对象。JavaScript 是一种基于对象的脚本语言,它不仅可以创建对象,也能使用现有的对象。

  3. 弱类型。JavaScript 语言中采用的是弱类型的变量类型,对使用的数据类型未做出严格的要求,是基于 Java 基本语句和控制的脚本语言,其设计简单紧凑。

  4. 动态性。JavaScript 是一种采用事件驱动的脚本语言,它不需要经过 Web 服务器就可以对用户的输入做出响应。

  5. 跨平台性。JavaScript 脚本语言不依赖于操作系统,仅需要浏览器的支持。

常见数据类型

基本类型:String、Number、Boolean、Null、Undefined、Symbol (ES6 新增)

引用类型:Object

类型检测方法

typeof ——基本类型检测

typeof是一元运算符,放在其单个操作数前面,可以是任意类型,返回值为标识操作数类型的一个字符串
返回数据类型为:string、boolean、number、Object、Function、undefined、symbol(ES6)


console.log(typeof 2);               // number
console.log(typeof true);            // boolean
console.log(typeof 'str');           // string
console.log(typeof []);              // object     []数组的数据类型在 typeof 中被解释为 object
console.log(typeof function(){});    // function
console.log(typeof {});              // object
console.log(typeof undefined);       // undefined
console.log(typeof null);            // object     null 的数据类型被 typeof 解释为 object

比较特殊的是typeof null返回“object”。
历史原因,规范尝试修改typeof null返回“null”修改完大量网站无法访问,为了兼容,或者说历史原因返回"object"。

typeof对基本类型函数对象很方便,但是其他类型就没办法了。

对象的判断常用instanceof

instanceof ——对象类型检测,检测的一定要是对象。

面向对象解释:instanceof 运算符左操作数是一个对象,右操作数标识对象的类。如果左侧的对象是右侧的类的实例,则表达式返回true,否则返回false。
原型链解释:instanceof 运算符用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性。

语法:object instanceof constructor
参数:object(要检测的对象.)constructor(某个构造函数) 注意点:null 和 undefined不是构造函数
描述:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

普通例子:


  var d = new Date();
  d instanceof Date; // true, d是由Date()创建的
  d instanceof Object; // true, 所有对象都是Object的实例
  d instanceof Number; // false
  var a = [1, 2, 3];
  a instanceof Array; // true
  a instanceof Object; // true
  a instanceof RegExp; // false
  

复杂例子:(这里的案例要有熟练的原型链的认识才能理解)


function Person() {}
console.log(Object instanceof Object);     //true
//第一个Object的原型链:Object=>
//Object.__proto__ => Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个Object的原型:Object=> Object.prototype

console.log(Function instanceof Function); //true
//第一个Function的原型链:Function=>Function.__proto__ => Function.prototype
//第二个Function的原型:Function=>Function.prototype

console.log(Function instanceof Object);   //true
//Function=>
//Function.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//Object => Object.prototype

console.log(Person instanceof Function);      //true
//Person=>Person.__proto__=>Function.prototype
//Function=>Function.prototype

console.log(String instanceof String);   //false
//第一个String的原型链:String=>
//String.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个String的原型链:String=>String.prototype

console.log(Boolean instanceof Boolean); //false
//第一个Boolean的原型链:Boolean=>
//Boolean.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个Boolean的原型链:Boolean=>Boolean.prototype

console.log(Person instanceof Person); //false
//第一个Person的原型链:Person=>
//Person.__proto__=>Function.prototype=>Function.prototype.__proto__=>Object.prototype
//第二个Person的原型链:Person=>Person.prototype

instanceof坑:不同window或iframe之间的对象类型检测不能使用instanceof!

相关连接:JS的instanceof到底是有多坑?

constructor——对象类型检测

任何对象都有constructor属性,继承自原型的,constructor会指向构造这个对象的构造器或者构造函数。
语法:object.construct
返回值: 对象的 construct 属性 返回创建该对象的 函数的引用

  • 除了一些特殊对象 其他对象都具备 构造器
    特殊对象:arguments、Enumerator、Error、Global、Math、RegExp、Regular Expression等

  • 对象中的 constructor属性 指向的函数本身,一般都有内置对象均具有 constructor 。
    如:Array、Boolean、Date、Function、Number、Object、String等。

console.log((2).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(('str').constructor === String); // true
console.log(([]).constructor === Array); // true
console.log((function() {}).constructor === Function); // true
console.log(({}).constructor === Object); // true

constructor可以被改写,所以使用要小心。


function Fn(){}; 
Fn.prototype=new Array();
 
var f=new Fn();
console.log(f.constructor===Fn);    // false
console.log(f.constructor===Array); // true 

Object.prototype.toString

精准的显示数据类型,改变对象的原型,他依然会显示正确的数据类型。
常用于判断内置对象,自定义对象不能区分(判断结果[object Object]);自定义对象判断使用instanceof


var a = Object.prototype.toString;

console.log(a.call(2)); //[object Number]
console.log(a.call(true)); //[object Boolean]
console.log(a.call('str')); //[object String]
console.log(a.call([])); //[object Array]
console.log(a.call(function() {})); //[object Function]
console.log(a.call({})); //[object Object]
console.log(a.call(undefined)); //[object Undefined]
console.log(a.call(null)); //[object Null]

注意:
很多对象继承 toString() 方法被重写了,为了调用正确的版本,必须间接地调用Function.call()方法,返回的字符串为 [object class]格式,所以提取第8个到倒数第2个位置之间的字符


  function classof(o) {
    if (o === null) return 'Null';
    if (o === undefined) return 'Undefined';
    return Object.prototype.toString.call(o).slice(8, -1);
  }
  

类型转换

显式转换

显示的转换数据类型主要通过JS定义的数据转换方法。

转换为:字符串类型

  • toString() 方法

数字、布尔值、字符串和对象都有 toString() 方法,但 null 和 undefined 没有。

  • String() 方法 ——原生函数(内建函数)返回基本类型;当作构造函数使用时(通过new)返回为对象;

这个方法能够将任何类型的值转换为字符串,基本的转换规则是:

  1. 如果值有toString()方法,则调用该方法进行转换;
  2. 如果值是null,则返回“null”;
  3. 如果值是undefined,则返回“undefined”。

转换为:数字类型

  • Number() 方法——原生函数(内建函数)返回基本类型;当作构造函数使用时(通过new)返回为对象;

这个方法可以用于任何数据类型,基本的转换规则是:

  1. 如果是Boolean值,true和false将分别被转换为1和0;
  2. 如果是数字值,只是简单的传入和返回;
  3. 如果是null值,返回0;
  4. 如果是undefined值,返回NaN;
  5. 如果是字符串,遵循下列规则:
    • 如果字符串中只包含数字,将其转换为十进制。即“123”转换为123,“011”转换为11(忽略前导0);
    • 如果字符串中包含有效的浮点格式,如“1.1”将其转换为对应的浮点数值(同样忽略前导0);
    • 如果字符串是空的,不包含任何字符,则将其转换为0;
    • 如果字符串中包含除上述以外的字符,则将其转换为NaN。
  6. 如果是对象,会首先检查该值是否有 valueOf() 方法。
    如果有,并且可以成功返回基本类型值,那么就使用该方法的返回值进行强制类型转换;
    如果没有就使用 toString() 的返回值来进行强制类型转换。如果 valueOf() 和 toString() 均不返回基本类型值,会产生 TypeError 错误。

由于Number()函数在转换字符串时比较复杂而且不够合理,因此在处理字符串的时候更常用的是parseInt()函数。

  • parseInt() 方法
    parseInt()函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字符串前面的空格,直至找到第一个非空格字符。

这个方法是专门用于把字符串转换成整数的,非字符串参数会首先被强制转换为字符串,它的基本转换规则是:

  1. 如果第一个字符不是数字或者负号,返回NaN;Number()对空字符返回0
  2. 如果第一个字符是数字,会继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符。

从 ES5 开始,parseInt() 默认转换为十进制数,如果需要转换其他基数(即多少进制),可以为这个函数提供第二个参数,例如:parseInt( “0xAF”, 16 ) 。

  • parseFloat()方法
    与parseInt()函数类似,parseFloat()也是从第一个字符(位置0)开始解析每个字符。而且也是一直解析到字符串末尾,或者解析到遇见一个无效的浮点数字字符为止。也就是说,字符串中的第一个小数点是有效的,而第二个小数点就是无效的了,因此它后面的字符串将被忽略。

转换为:Boolean类型

  • Boolean() 方法——原生函数(内建函数)返回基本类型;当作构造函数使用时(通过new)返回为对象;

可以对任何数据类型的值调用 Boolean() 方法,而且总会返回一个 Boolean 值,基本的转换规则是:

  1. 以下这些是可以被转换为 false 的值:
    • undefined
    • null
    • false
    • +0、-0 和 NaN
    • “”
  2. 上面列举之外的值都是可以被转换为 true 的值。

所有的对象都是可以被转换为 true 的值,包括使用Boolean、 Number 和 String 来创建的基本包装类型的对象。

隐式转换

内部调用的都是显式类型转换的方法;在JS中有一些操作符或者语句会进行数据转换。

递增递减运算符(前置、后置)++/--; 正负运算符 +/-

非数字到数字的类型转换:返回结果为number类型

先将参数进行数值类型转换:Number()方法

  1. 如果包含的是有效数字字符串或者是有效浮点数字符串,则会将字符串转换(Number())为数值,再进行加减操作,返回值的类型是:number类型。
  2. 如果不包含有效数字字符串,则会将字符串的值转换为NaN,返回值的类型是:number类型。
  3. 如果是boolean类型,则先会把true或者false转换为1或者0,再进行加减操作,返回值的类型是:number类型。
  4. 如果是null类型,则先会把null转换为0,在进行加减操作,返回值的类型是:number类型。
  5. 如果是undefined,则先会把undefined转换为NaN,再进行加减操作,返回值的类型是:number类型。
  6. 如果是对象,则先会通过对象的valueOf()方法,进行转换,如果返回的是NaN,调用toString()方法,在进行前面的操作,返回值的类型 是:number类型。(注:空数组[]会返回0,在进行加减操作,空对象则会返回NaN)。

四则运算 + - * / %

非数字到数字的类型转换+ 运算符有特殊情况):返回结果为number类型,字符串类型(+ 运算符),或者NaN

  1. 加法运算符+是双目运算符,只要其中一个是String类型,表达式的值便是一个String。(加号运算符( + )即能用于数字加法,也能用于字符串拼接。)
  2. 对于其他的四则运算,只有其中一个是Number类型,表达式的值便是一个Number。
  3. 对于非法字符的情况通常会返回NaN
**说明:**
  • 字符串加数字,数字就会转成字符串。
  • 数字减字符串,字符串转成数字。如果字符串不是纯数字就会转成NaN。字符串减数字也一样。两个字符串相减也先转成数字。
  • 乘,除,大于,小于跟减的转换也是一样。

关系操作符 > / < / >= / <=

  • 如果两个操作值都是数值,则直接比较大小。
  • 如果两个操作值都是字符串,则字符串进行其Unicode编码进行比较。
  • 如果一个操作值是数值,则另一个值转换为数值进行比较。
  • 如果一个操作值是对象,则调用对象的valueOf()和toString()方法,然后再进行上述比较。
  • 如果一个操作值是布尔值,则将布尔值转换为数值再进行比较。
    (注:NaN和任何值都不相等,包括自己,同时它与任何类型比较都会返回false。)

相等操作符 =====

== 需要做类型转换再比较; === 不做类型转换比较

  • 布尔值、字符串和数值进行比较,会先将其转换为数值再进行比较。
  • null和undefined比较是相等的,但不是全等的。
  • NaN与任何值都不相等,都会返回false。
**说明:**

关于==
1.undefined等于null
2.字符串和数字比较时,字符串转数字
3.数字为布尔比较时,布尔转数字
4.字符串和布尔比较时,两者转数字

逻辑操作符

只有undefined、null、NaN、0、空字符串会被转换为false,其余都为true

逻辑操作符一般用于语句判断中。通过判断结果返回的值进行后面的语句操作。

  • 逻辑非(!)操作符:首先会通过Boolean()函数将其操作值转换为布尔值,然后求反。
  • 逻辑与(&&)操作符:如果第一个值经过Boolean()函数转换后为true,则返回第二个操作值,否则返回第一个操作值。如果有一个操作值为null这返回null,如果有一个操作值为undefined,则返回undefined,如果有一个值为NaN,则返回NaN。
  • 逻辑或(||)操作符:如果第一个值经过Boolean()函数转换为false,则返回第二个操作值,否则返回第一个操作值。(注:逻辑操作符的运算为短路逻辑运算:前一个条件已经能够得出结果后续条件不再执行!)

语句中发生类型转换

下面列举的情况都会发生布尔值隐式类型转换:

  1. if () 语句中的条件判断表达式;
  2. for ( … ; … ; … ) 语句中的条件判断表达式(第二个);
  3. while () 和 do…while() 循环中的条件判断表达式;
  4. ? : 中的条件判断表达式;

对象转换为基础类型

基本转换步骤:

  • 转化为 Boolean类型
    所有的对象(包括数字和函数)都转换为true。
  • 转化为字符串类型
  1. 如果对象有 toString() , 调用, 如返回原始值, 则转换成字符串并返回;
  2. 上述不成立, 调用valueOf(),如返回原始值, 则转换成字符串并返回;
  3. 如不能返回原始值 , 则抛出类型错误异常。
  • 转化为数字类型
  1. 如果有 valueOf() , 调用并返回原始值, 则转换为数字并返回;
  2. 上述不成立, 调用toString(), 如返回原始值 , 则转换为数字并返回;
  3. 如不能返回原始值 , 则抛出类型错误异常。

特殊转换:

“+”、“==”、“!=” 和 关系运算符 :对象的特殊转化行为

  • 非Date类对象(将对象转化为基础类型,然后返回,不强制转化为数字或字符
    按照对象转化为数字类型的步骤(仅是步骤,先valueOf 在 toString);注意:不同于基本步骤,通过valueOf()或toString()返回的原始值将被直接使用,而不会被强制转换为数字或字符串。
let obj = {
    valueOf: function() {
        // return '123'
        // return
        // return true
        // return {}
        // return 3
    },

    toString: function() {
        return 2
    }
}

obj = obj + 1

console.log(obj)

// 1231
// NaN
// 2
// 3
// 4
  • Date类对象(将对象转化为字符串类型
    对象按照转化为字符串的步骤;

总结:
“+”、“==”、“!=”和关系运算符是唯一执行这种特殊的字符串到原始值的转换方式的运算符。
其他运算符到特定类型的转换都很明确,而且对日期对象来讲也没有特殊情况。
例如“-”(减号)运算符把它的两个操作数都转换为数字。

对象属性检测和循环访问

hasOwnProperty()

判断属性是否为对象自有属性(仅在实例中)返回boolen;
可以检测一个属性是存在于实例中,还是存在于原型中。
这个方法(不要忘了它是从 Object 继承来的)只在给定属性存在于对象实例中时,才会返回 true。

in 操作符

in 操作符会在通过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原型中
判断属性是否在对象中(不分实例和原型) 返回boolen

for-in

在使用 for-in 循环时,返回的是所有能够通过对象访问的、可枚举的( enumerated)属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性
返回对象可访问,可枚举属性(不分实例和原型

for-of

可迭代对象(包括 Array,Map,Set,String,TypedArray,arguments 对象等等)上创建一个迭代循环枚举属性;

Object.keys()方法

返回对象自身的所有可枚举的属性的键名(仅在实例中)返回字符串数组

Object.getOwnPropertyNames()方法

返回对象上所有(不管是否可枚举)的实例属性(仅在实例中)返回字符串数组

总结:

in 操作符,其他所有方式操作的都是对象自身(仅在实例中)的属性

Blob和ArrayBuffer

Blob

Blob(binary large object),二进制类文件大对象,是一个可以存储二进制文件的“容器”,HTML5中的Blob对象除了存放二进制数据外还可以设置这个数据的MIME类型。File接口基于Blob,继承了 blob 的功能并将其扩展使其支持用户系统上的文件。
Blob构造函数接受两个参数,第一个参数是一个包含实际数据的数组,第二个参数是数据的MIME类型。
Blob.size : blob对象的数据大小
Blob.type : 表示blob对象所包含数据的MIME类型。如果实例化时未指明类型,则该值为空字符串。

ArrayBuffer

ArrayBuffer对象表示内存中一段原始的二进制数据容器(缓冲区),具体介绍请参考以下链接。
http://javascript.ruanyifeng.com/stdlib/arraybuffer.html

总结:

  • Blob和ArrayBuffer都能存储二进制数据。Blob相对而言储存的二进制数据大(如File文件对象)。
  • ArrayBuffer对象表示原始的二进制数据缓冲区,即在内存中分配指定大小的二进制缓冲区(容器),用于存储各种类型化数组的数据,是最基础的原始数据容器,无法直接读取或写入, 需要通过具体视图来读取或写入,即TypedArray对象或DataView对象对内存大小进行读取或写入;
    Blob对象表示一个不可变、原始数据的类文件对象。
  • 可以相互转换

Blob => ArrayBuffer

let blob = new Blob([1,2,3,4])
let reader = new FileReader();
reader.onload = function(result) {
    console.log(result);
}
reader.readAsArrayBuffer(blob);

ArrayBuffer => Blob

let blob = new Blob([buffer])
  • ArrayBuffer是原始的二进制数据缓冲区,不能设置MIME类型;Blob可以储存大量的二进制编码格式的数据,可以设置对象的MIME类型。

函数

caller 和 callee

  • caller 返回一个调用当前函数的引用 如果是由顶层调用的话 则返回 null
  • callee 返回一个正在被执行函数的引用 (这里常用来递归匿名函数本身 但是在严格模式下不可行)
    callee 是 arguments 对象的一个成员 表示对函数对象本身的引用 它有个 length 属性(代表形参的长度)
var callerTest = function() {
    console.log(callerTest.caller);
};

function a() {
    callerTest();
}
a(); //输出function a() {callerTest();}
callerTest(); //输出null


var c = function(x, y) {
    console.log(arguments.length, arguments.callee.length, arguments.callee);
};

//输出3 2 function(x,y) {console.log(arguments.length,arguments.callee.length,arguments.callee)}
c(1, 2, 3);

事件

event.target 和 event.currentTarget区别

  • event.target
    返回触发事件的元素
  • event.currentTarget
    返回绑定事件的元素

移动端 click 事件、touch 事件、tap 事件

  • click 事件在移动端会有 200-300ms ms 的延迟
    移动浏览器提供一个特殊的功能:双击(double tap)放大
    300ms的延迟就来自这里,用户碰触页面之后,需要等待一段时间来判断是不是双击(double tap)动作,而不是立即响应单击(click),等待的这段时间大约是300ms。

  • touch 事件是针对触屏手机上的触摸事件。
    其中包括:touchstart,touchmove,touchend,touchcancel 这四个事件,
    touchstart touchmove touchend 事件可以类比于 mousedown mouseover mouseup 的触发

  • tap 事件在移动端,代替 click 作为点击事件(自行封装的单击事件)
    移动事件提供了touchstart、touchmove、touchend却没有提供tap支持,主流框架(库)都是手动实现了自定义tap事件,以求消除300ms延迟,提高页面响应速度。tap事件利用原生的touch 事件模拟没有延迟的click事件。

使用原生touch事件(包括tap事件)存在点击穿透的问题

混用touch和click肯定会导致点透问题

  • 用户手指接触屏幕会触发:touchstart和click事件;
  • touchstart事件优先触发(所有移动端事件优先触发)
  • click事件的触发有200-300ms的延时

如果前面的元素触发touch事件后被隐藏,后面的元素将被触发click(如果后面元素有click事件)

案例和解决方案:
点透事件 移动页面点击穿透问题解决方案

普通事件和事件绑定

普通事件(DOM0级事件处理程序) : 通过 JavaScript 指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
事件绑定(DOM2级事件处理程序) : 可以添加多个事件处理程序。

  • 普通事件中的onclick是DOM0级事件只支持单个事件,会被后定义的onclick事件覆盖,
  • 事件绑定中的addEventListener是DOM2级事件可以添加多个事件而不用担心被覆盖.
// 普通事件
element.onclick = function(){
        // ...
    };

// 事件绑定
element.addEventListener(onclick, handler, false);

事件绑定的差异和兼容性方案

标准事件API : addEventListener() 和 removeEventListener()
IE事件API : attachEvent()和 detachEvent()

  • 标准API事件名参数:如click ;IE事件API事件名参数:如onclick。
  • 方法作用域不同:标准API为当前元素(方法中this为当前事件触发对象),IE事件API为全局对象(方法中this为windows)
  • 多个同名事件绑定程序的执行顺序不同:标准API顺序:根据绑定顺序,IE事件API顺序:以相反的顺序触发。
* 事件绑定 兼容性方案 (没有考虑事件作用域问题)
var EventUtil = {
    /**
     * 
     * @param {*} element 绑定事件元素
     * @param {*} type    绑定事件类型
     * @param {*} handler 事件处理回调函数
     */
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    }
};

事件对象的差异和兼容性方案

在触发 DOM 上的某个事件时,会产生一个事件对象 event,这个对象中包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。所有浏览器都支持 event 对象,但支持方式不同。
主要差异

  • event获取方式不同:
    标准API:无论何种绑定事件方式;向事件处理回调函数传入参数(如event),都可获取event对象
    IE:取决于绑定事件处理回调函的方式:
    • 通过普通事件绑定(DOM0):event 对象作为 window 对象的一个属性存在;通过 window.event 取得了 event 对象。
    • 通过事件绑定(DOM2):向事件处理回调函数传入参数(如event),可获取event对象;也可以通过 window 对象来访问 event 对象,就像使用DOM0 级方法时一样。
    • 通过HTML特性绑定:还可以通过一个名叫 event 的变量来访问 event对象
  • 取消默认事件:
    标准API:preventDefault() 方法;IE:属性 returnValue = false
  • 取消冒泡:
    标准API:stopPropagation() 注:stopPropagation可同时取消事件捕获和冒泡
    IE:属性 cancelBubble = true 注:IE只有事件冒泡,cancelBubble 只能取消冒泡
  • 获取实际目标元素:
    标准API:属性 target;IE:属性 srcElement
* 事件对象 兼容性方案 ( 针对前面事件绑定兼容性方案的加以增强 )
var EventUtil = {
    addHandler: function(element, type, handler) {
        if (element.addEventListener) {
            element.addEventListener(type, handler, false);
        } else if (element.attachEvent) {
            element.attachEvent("on" + type, handler);
        } else {
            element["on" + type] = handler;
        }
    },
    getEvent: function(event) {
        return event ? event : window.event;
    },
    getTarget: function(event) {
        return event.target || event.srcElement;
    },
    preventDefault: function(event) {
        if (event.preventDefault) {
            event.preventDefault();
        } else {
            event.returnValue = false;
        }
    },
    removeHandler: function(element, type, handler) {
        if (element.removeEventListener) {
            element.removeEventListener(type, handler, false);
        } else if (element.detachEvent) {
            element.detachEvent("on" + type, handler);
        } else {
            element["on" + type] = null;
        }
    },
    stopPropagation: function(event) {
        if (event.stopPropagation) {
            event.stopPropagation();
        } else {
            event.cancelBubble = true;
        }
    }
};

网络

防抖(debounce) 和 节流(thorttle)

在发生持续触发事件时,防抖设置事件延迟并在空闲时间去触发事件,而节流则是隔一定的时间触发一次。

防抖(debounce)

在函数需要频繁触发时,只有当有足够空闲的时间时,才执行一次。
就好像在百度搜索时,每次输入之后都有联想词弹出,这个控制联想词的方法就不可能是输入框内容一改变就触发的,他一定是当你结束输入一段时间之后才会触发。

节流(thorttle)

预定一个函数只有在大于等于执行周期时才执行,周期内调用不执行。
就好像你在淘宝抢购某一件限量热卖商品时,你不断点刷新点购买,可是总有一段时间你点上是没有效果,这里就用到了节流,就是怕点的太快导致系统出现bug。

ajax,Fetch,axios

  • ajax
    传统 Ajax 指的是 XMLHttpRequest(XHR), 最早出现的发送后端请求技术,隶属于原始js中,核心使用XMLHttpRequest对象,多个请求之间如果有先后关系的话,就会出现回调地狱。
  • axios
    axios 是一个基于Promise 用于浏览器和 nodejs 的 HTTP 客户端,本质上也是对原生XHR的封装,只不过它是Promise的实现版本,符合最新的ES规范
  • Fetch
    fetch号称是AJAX的替代品,是在ES6出现的,使用了ES6中的promise对象。Fetch是基于promise设计的。Fetch的代码结构比起ajax简单多了,参数有点像jQuery ajax。但是,一定记住fetch不是ajax的进一步封装,而是原生js,没有使用XMLHttpRequest对象。
 总结:axios既提供了并发的封装,也没有fetch的各种问题,而且体积也较小,当之无愧现在最应该选用的请求的方式。

模块化

require 与 import 的区别

  • 两者的加载方式不同,require 是在运行时加载(返回一个对象,输出的是一个值的拷贝),而 import 是在编译时加载,编译时输出接口(输出的是值的引用。)
    CommonJS 加载的是一个对象(即module.exports属性),该对象只有在脚本运行完才会生成。而 ES6 模块不是对象它的对外接口只是一种静态定义,在代码静态解析阶段就会生成
    JS 引擎对脚本静态分析的时候,遇到模块加载命令import,就会生成一个只读引用等到脚本真正执行时,再根据这个只读引用,到被加载的那个模块里面去取值。换句话说,ES6 的import有点像 Unix 系统的“符号连接”,原始值变了,import加载的值也会跟着变。因此,ES6 模块是动态引用并且不会缓存值,模块里面的变量绑定其所在的模块。

  • 规范不同,require 是 CommonJS/AMD 规范,import 是 ESMAScript6+规范

  • require 特点:社区方案,提供了服务器/浏览器的模块加载方案。非语言层面的标准。只能在运行时确定模块的依赖关系及输入/输出的变量,无法进行静态优化。

import 特点:语言规格层面支持模块功能。支持编译时静态分析,便于 JS 引入宏和类型检验,动态绑定。

面向对象设计

JS 创建对象方式

  • Object构造函数和象字面量表示法 创建对象
    它们使用同一接口创建对象,会产生大量重复代码,可将代码抽离封装成为函数
  • 工厂模式 创建对象
    将同一接口,封装为函数,返回对象;但是未区别对象类型;
  • 构造函数 创建对象
    根据特定构造函数创建对象,能区分函数类型,但是同类型对象创建,会造成属性和方法的大量重复造成资源浪费,无法复用。
  • 原型 创建对象
    使用原型创建对象的方式,可以让所有对象实例共享它所包含的属性和方法。但是对象没有属于自己的实例属性和方法。
  • 组合方式 创建对象
    使用构造函数模式与原型模式结合的方式,构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性

JS 继承方式

  • 原型链继承
    缺点:

    • 引用类型的属性被所有实例共享
    • 在创建 Child 的实例时,不能向 Parent 传参
  • 借用构造函数
    优点:

    • 避免了引用类型的属性被所有实例共享
    • 可以在 Child 中向 Parent 传参

    缺点:

    • 方法都在构造函数中定义,每次创建实例都会创建一遍方法。
  • 组合继承
    优点:

    • 融合原型链继承和构造函数的优点,是 JavaScript 中最常用的继承模式。
  • 原型式继承
    缺点:

    • 包含引用类型的属性值始终都会共享相应的值,这点跟原型链继承一样。
  • 寄生式继承
    缺点:

    • 跟借用构造函数模式一样,每次创建对象都会创建一遍方法。
  • 寄生组合式继承
    优点:

    • 这种方式的高效率体现它只调用了一次 Parent 构造函数,并且因此避免了在 Parent.prototype 上面创建不必要的、多余的属性。
    • 与此同时,原型链还能保持不变
    • 因此,还能够正常使用 instanceof 和 isPrototypeOf
    • 开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式

HTML5

HashChange 和 History 区别

  • HashChange : 监听片段标识符(hash值,URL的#号后面的部分)的变化;
  • History : 管理历史状态(通过“后退”和“前进”按钮 或者 history.go和history.back 来切换历史状态)

通过 hashchange 事件,可以知道 URL 的参数什么时候发生了变化,即什么时候该有所反应。
而通 过 状 态 管 理 API , 能 够 在 不 加 载 新 页 面 的 情 况 下 改 变 浏 览 器 的 URL 。

元素宽高:offsetWidth/offsetHeight,clientWidth/clientHeight 与 scrollWidth/scrollHeight

  • offsetWidth
    返回元素的宽度(包括元素宽度、内边距和边框,不包括外边距)-元素实际宽度
  • offsetHeight
    返回元素的高度(包括元素高度、内边距和边框,不包括外边距)-元素实际高度
  • clientWidth
    返回元素的宽度(包括元素宽度、内边距,不包括边框和外边距)-可视内容宽度
  • clientHeight
    返回元素的高度(包括元素高度、内边距,不包括边框和外边距)-可视内容高度
  • style.width
    返回元素的宽度(包括元素宽度,不包括内边距、边框和外边距)-设置的内容区宽度
  • style.height
    返回元素的高度(包括元素高度,不包括内边距、边框和外边距)-设置的内容区高度
  • scrollWidth
    返回元素的宽度(包括元素宽度、内边距和溢出尺寸,不包括边框和外边距),无溢出的情况,与clientWidth相同 -实际内容宽度
  • scrollHeigh
    返回元素的高度(包括元素高度、内边距和溢出尺寸,不包括边框和外边距),无溢出的情况,与clientHeight相同 -实际内容高度

相对距离:offsetTop/offsetLeft,scrollLeft/scrollTop

  • offsetTop
    返回元素的上外缘距离最近采用定位父元素内壁的距离,如果父元素中没有采用定位的,则是获取上外边缘距离文档内壁的距离。
    所谓的定位就是position属性值为relative、 absolute或者fixed。 返回值是一个整数, 单位是像素。 此属性是只读的。
  • offsetLeft
    此属性和offsetTop的原理是一样的,只不过方位不同,这里就不多介绍了。
  • scrollLeft
    此属性可以获取或者设置对象的最左边到对象在当前窗口显示的范围内的左边的距离,也就是元素被滚动条向左拉动的距离。
    返回值是一个整数, 单位是像素。 此属性是可读写的。
  • scrollTop
    此属性可以获取或者设置对象的最顶部到对象在当前窗口显示的范围内的顶边的距离,也就是元素滚动条被向下拉动的距离。
    返回值是一个整数, 单位是像素。 此属性是可读写的。

鼠标定位:clientX/clientY,pageX/pageY,screenX/screenY,offsetX/offsetY

不管是onclick, 还是omousemove, onmouseover等

  • clientX 鼠标相对于浏览器( 这里说的是浏览器的有效区域) 左上角x轴的坐标; 不随滚动条滚动而改变;(相对于可视区域)
  • clientY 鼠标相对于浏览器( 这里说的是浏览器的有效区域) 左上角y轴的坐标; 不随滚动条滚动而改变;(相对于可视区域)
  • pageX 鼠标相对于浏览器( 这里说的是浏览器的有效区域) 左上角x轴的坐标; 随滚动条滚动而改变;(相对于整个页面区域)
  • pageY 鼠标相对于浏览器( 这里说的是浏览器的有效区域) 左上角y轴的坐标; 随滚动条滚动而改变;(相对于整个页面区域)
  • screenX 鼠标相对于显示器屏幕左上角x轴的坐标;
  • screenY 鼠标相对于显示器屏幕左上角y轴的坐标;
  • offsetX 鼠标相对于事件源左上角X轴的坐标
  • offsetY 鼠标相对于事件源左上角Y轴的坐标

浏览器的可视区域宽度和高度 兼容

  • 浏览器的可视区域宽度和高度
  • window.innerWidth(innerHeight) 大部分浏览器主持 IE8及其以下浏览器不支持
  • document.documentElement.clientWidth(clientHeight) HTML标准模式支持
  • document.body.clientWidth(clientHeight) 怪异模式支持
var clientWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth
var clientHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight

浏览器的滚动条的滚动宽度和高度 兼容

  • 浏览器的滚动条的滚动宽度和高度
  • window.pageXOffset(pageYOffset) 大部分浏览器支持 IE8及其以下浏览器不支持
  • documnet.documentElement.scrollLet(scrollTop) HTML标准模式支持
  • ducument.body.scrollLet(scrollTop) 怪异模式支持
var x = window.pageXOffset || ducument.documentElement.scrollLet || ducument.body.scrollLet
var y = window.pageYOffset || ducument.documentElement.scrollTop || ducument.body.scrollTop

ES6

posted @ 2023-05-28 23:54  CD、小月  阅读(31)  评论(0编辑  收藏  举报