JavaScript

数据类型

基本数据类型:String、Number、Boolean、Null、undefined、Symbol(es6新增,表示独一无二的值)、BigInt(es6? 新增)

引用数据类型:Object、Array、Function

数据类型判断

js检测数据类型四种办法open in new window

typeof

// 只能判断基本数据类型
console.log( typeof "a" ); // string
console.log( typeof 1 ); // number
console.log( typeof true ); // boolean

console.log( typeof [] ); // object
console.log( typeof {} ); // object
console.log( typeof function(){} ); // function

console.log( typeof null ); // object
console.log( typeof undefined ); // undefined

instanceof

console.log("a" instanceof String); // false
console.log(1 instanceof Number); // false
console.log(true instanceof Boolean); // false

console.log(new String('a') instanceof String) // true
console.log(new Number(1) instanceof Number) // true
console.log(new Boolean(true) instanceof Boolean) // true

console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(function(){} instanceof Function); // true

console.log(null instanceof Null); // ❌ Null is not defined
console.log(undefined instanceof Undefined); // ❌ Undefined is not defined

constructor

console.log(("1").constructor === String); // true
console.log((1).constructor === Number); // true
console.log((true).constructor === Boolean); // true

console.log(([]).constructor === Array); // true
console.log(({}).constructor === Object); // true
console.log((function() {}).constructor === Function); // true

console.log((null).constructor === Null); // ❌ Cannot read property 'constructor' of null
console.log((undefined).constructor === Undefined); // ❌ Cannot read property 'constructor' of undefined

// 改动原型判断会出错
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.call()

console.log( Object.prototype.toString.call("aaa") ); // [object String]
console.log( Object.prototype.toString.call(1)); // [object Number]
console.log( Object.prototype.toString.call(true) ); // [object Boolean]

console.log( Object.prototype.toString.call([]) ); // [object Array]
console.log( Object.prototype.toString.call({}) ); // [object Object]
console.log( Object.prototype.toString.call(function() {}) ); // [object Function]

console.log( Object.prototype.toString.call(null) ); // [object Null]
console.log( Object.prototype.toString.call(undefined) ); // [object Undefine]

// 改动原型仍可得正确结果
function Fn(){};
Fn.prototype = new Array();
console.log( Object.prototype.toString.call(Fn) ); // [object Function]

深浅拷贝

参考文章:JavaScript 中的深浅拷贝(👍,一目了然)open in new window

原因

1、基本类型和引用类型在内存中的存储方式不同。

基本数据类型保存在栈内存(保存大小一致的数据);

引用数据类型保存在堆内存(保存大小不一致的数据),但引用类型的地址保存在栈内存;

2、JS 对基本类型和引用类型的处理不同。

基本数据类型指的是简单的数据段;

引用数据类型指的是一个对象保存在堆内存中的地址;

JS 不允许直接操作内存中的地址,也就是不能操作对象的内存空间,所以对对象的操作都只是在操作它的引用而已。 即复制对象的时候,实际复制的是对象存储的堆地址,而不是对象本身,复制后2个指针指向的都是同一个内存里的对象,所以改变其中一个会影响另一个。

概念

浅拷贝只是复制基本类型的数据或者指向某个对象的指针,而不是对象本身;

源对象和目标对象共享同一块内存

修改目标对象,源对象也可能修改;

深拷贝实现真正意义上的对象的拷贝,拷贝的是对象的值,内存地址不一样;

目标对象跟源对象不共享内存

修改目标对象,源对象不会被修改;

实现

深拷贝实现方法递归调用浅拷贝

数组操作方法

Array对象open in new window

字符串操作方法

Object对象open in new window

DOM事件模型

DOM事件模型:包括捕获冒泡(IE)两个过程,捕获是从上往下到达目标元素,冒泡是从目标元素往上到达 window。

捕获具体流程window —> document —> html —> body —> 父级...子级 —> 目标元素

冒泡具体流程目标元素 —> 子级...父级 —> body —> html —> document —> window

DOM0级事件模型

只能注册一个事处处理程序

注册销毁:document.querySelector('button'). = handledocument.querySelector('button'). = null

DOM2级事件模型

可注册多个事处处理程序

W3C标准模型

三个过程:事件捕获阶段事件处理阶段事件冒泡阶段

注册销毁:addEventListenerremoveEventListener

IE事件模型

两个过程:事件处理阶段事件冒泡阶段

注册销毁:attachEvent()detachEvent()

DOM3级事件模型

UI事件:当用户与页面上的元素交互时触发,如:loadscroll;

焦点事件:当元素获得或失去焦点时触发,如:blurfocus;

鼠标事件:当用户通过鼠标在页面执行操作时触发,如:dbclickmouseup

滚轮事件:当使用鼠标滚轮或类似设备时触发,如:mousewheel

文本事件:当在文档中输入文本时触发,如:inputchange

键盘事件:当用户通过键盘在页面上执行操作时触发,如:keydownkeypress

合成事件:当为IME(输入法编辑器)输入字符时触发,如:compositionstart

变动事件:当底层DOM结构发生变化时触发,如:DOMsubtreeModified

自定义事件模型

on用于绑定事件,参数:事件名称,事件处理函数;

emit用于触发事件,参数:事件名称,传递给事件处理函数的参数;

off 用于解除绑定的指定事件, 参数:事件名称,要解绑的事件函数;

one 用于绑定一次性事件只能触发一次,参数:事件名称,事件处理函数;

摘抄并整理自 作者:泛舟湖上清波郎朗 链接:https://www.imooc.com/article/50745open in new window 来源:慕课网

移动端触摸事件

touchstart:当手指触摸屏幕时触发;

touchmove:当手指在屏幕上滑动时连续地触发;

touchend:当手指从屏幕上移开时触发;

touchcancel:当系统停止跟踪触摸时触发。可解决部分安卓手机不触发 touchend 的问题。

e.preventDefault();

e.stopPropagation()

点透问题

事件触发顺序

touchstart —> touchmove —> touchend —> click

点透场景

B元素在A元素上方,B元素绑定并触发 touchstart 事件关闭B元素后,A元素触发了click 事件。

点透原因

事件 touchendclick 之间会有 300ms 左右的延时,用来判断用否是否双击。在上层元素关闭时,如果下方元素有click事件则很可能出现点透问题。

解决方案

1、zepto 的 tap 事件,tap 事件会在 touchstart 和 touchend 记录位置数据,判断是点击还是滑动;

2、meta 标签的 viewport 设置 user-scalable=no" 禁止用户缩放;

3、css 的 touch-action

4、js 阻止默认事件或冒泡;

事件代理(事件委托)

含义

当我们需要对很多元素添加事件的时候,可以通过将事件添加到它们的父节点而将事件委托给父节点来触发处理函数。

原理

浏览器的事件冒泡机制。

优点

1、管理的函数变少了;

2、方便动态的添加和修改元素,而不用修改事件绑定;

3、减少了因循环引用而带来的内存泄漏发生的概率;

为什么 vue 没有事件代理

......

// javascript
document.getElementById("parent").addEventListener("click",function(e) {
  if(e.target && e.target.nodeName.toUpperCase == "LI") {
    // e.target 真正点击的元素
  }
});

// vue
myclick(e) {
  if (e.target.nodeName.toUpperCase === 'LI') {
    // e.target 真正点击的元素
  }
}

// jquery
$("#parent").delegate("a", "click", function(){
  // $(this) 真正点击的元素
});