JavaScript原理(二)

一、DOM性能

1、尽量较少DOM节点的操作(增,删,改,查)。因此对于DOM的操作都尽量进行变量缓存。

2、使用HTML集合优化(类数组,但是没数组的方法)。

document.getElementsByClassName()
document.getElementsByName()
document.getElementsByTagName()

如果需要多次使用集合,可以考虑将集合复制到一个数组。(复制会遍历一次集合,因此要做合理考虑,是否值得复制)

var coll = document.getElementsByTagName('div');
var length = coll.length;
var arr = []
for (var i = 0; i < length; i ++) {
  arr[i] = coll[i]
}
console.log(arr)
console.log(arr.push(3));
console.log(coll.push(3)); // coll.push is not a function

3、遍历children 要比childNodes更快,而在IE下更明显。

4、如果支持querySelectorAll(),尽可能采用它,该方法不反回集合,不会有集合的性能问题。

5、减少DOM重绘或重排次数。

  1. 增、删可见DOM
  2. 位置改变
  3. 尺寸改变
  4. 内容改变,文字变图片
  5. 浏览器窗口改变

5.1、优化方法一,合并

// 两次的样式改变,都会导致重绘
document.getElementById('add').style.padding = '1px';
document.getElementById('add').style.margin = '3px';

// 将多次操作合并为一次,只重绘一次
document.getElementById('add').style.cssText = 'padding: 1px;margin: 3px;'

5.2、优化方法二,对样式的操作,改为类名的变换

document.getElementById('add').className = 'change'

5.3、优化方法三、对于多次重复操作,采用从文档流摘除,多次操作,添加回文档

例:ul里有两条数据,现在需要对其进行宽度和高度的修改,并增加三条数据。
第一步:移除存在的li。活着uldisplay改为none,(对隐藏的DOM修改,不会重绘)
第二步:(记住li的结构)用字符串拼接好这两个li,填写宽高的行内样式。并且与新增的三条拼接上,(这期间都是字符操作,并不会导致DOM重绘)
第三步:添加到ul里。

二、DOM原型继承

符合DOM标准的浏览器都支持HTMLElement类。DOM文档中所有元素都继承这个类,HTMLElement又继承于Element,Element继承于Node类。

// HTMLElement的prototype上,有着各种原生的DOM操作方法。而我们也可以写自己的方法。(ie是玩不了的,不过有高人提供了方法,有兴趣可以搜索)

HTMLElement.prototype.zzz = function () {
  console.log(this.id)
}
document.getElementById('add').zzz();

三、鼠标拖放

mousemove
1、清楚几个坐标:按下鼠标时的指针坐标,移动中当前指针坐标,松开时的指针坐标,拖放元素的原始位置,拖动中的元素坐标。
2、各个位置,对应的关系,和兼容性。MDN
3、鼠标拖动事件,主要是基于mousedown 和mouseup 和 mousemove三个事件,用来处理不同时期的不同需求。

四、对象

1、原型链

Object.prototype.a = 1;
Function.prototype.a = 2;
console.log(Object.a); // 2
console.log(Function.a);  // 2
var obj = {};
console.log(obj.a); // 1
var f = Object;  
console.log(f.a);  // 2
var f2 = new Function();
console.log(f2.a);  // 2
var obj2 = new Object();
console.log(obj2.a); // 1

这里写图片描述

2、用hasOwnProperty()方法过滤原型属性。用typeof过滤方法。

3、封装类继承,

// 封装函数
function extant (Sub, Sup) {  
// 定义一个空函数 ,用来实现功能中转,避免因为超类太大,实例产型大量的系统消耗。
  var F = function () {};  

  F.prototype = Sup.prototype; // 设置空函数的原型为超类的原型
  Sub.prototype = new F();  // 实例化原型,并把超类的原型引用传递给子类。
  Sub.prototype.constructor = Sub; // 恢复子类构造器为自身。
  Sub.Sup = Sup.prototype;
  if (Sub.prototype.constructor == Object.prototype.constructor) {
    Sup.prototype.constructor = Sup;
  }
}

// 超类
function A (x) {
  this.x = x;
}
A.prototype.add = function () {
  return this.x + this.x
}
A.prototype.mul = function () {
  return this.x * this.x
}

// 子类
function B (x) {
  A.call(this, x);
}
// 调用封装
extant(B, A);

// 如果子类同样定义了,add方法,会导致超类的被覆盖。
// B.prototype.add = function () {
//  return this.x + ' 4 ' + this.x
//}
// 采用该方式调用,避免耦合,Sub.Sup = Sup.prototype;该语句的作用
//B.prototype.add = function () {
//  return B.Sup.add.call(this);
//}

var f = new B(5);
console.log(f.add()) // 10
console.log(f.mul()) // 25

4、重载:同名方法有多个实现。重载和覆盖是完全不同的东西。

对于那些提供可选参数的方法,都可以算是重载

// 可以实现任意个参数的求和,(多个实现)
function f () {
  var sum = 0;
  for (var i = 0; i < arguments.length; i ++) {
    if (typeof arguments[i] === 'number') {
      sum += arguments[i]
    }
  }
  return sum;
}
console.log(f(3,5,7,9))

5、覆盖:子类中定义的方法与超类同名,并且参数类型和个数都相同,当子类实例化后,超类的同名方法将被隐藏。(反正就是你能理解的那种覆盖就对了)

五、错误捕获

函数内部发生了错误,如果自身没有捕获,错误就会沿着函数调用链向上抛出,直到被JavaScript引擎捕获,代码终止执行。

// 由于错误会沿着函数调用向上抛,所以不必所有函数都进行错误捕获,可以在主要的位置进行即可
function main(s) {
  console.log('开始 main()');
  try {
    foo(s);
  } catch (e) {
    console.log(e);
  }
  // 如果该处为捕获的话,会导致代码终止结束无法输出。合理利用捕获,保证代码的健壮性。
  console.log('结束');
}

function foo(s) {
  console.log('开始 foo()');
  func(s);
}

function func(s) {
  console.log('开始 func()');
  console.log(s.name);
}

main(null);

对于异步调用和js的绑定事件,不能直接在外部捕获。

无效示例:
    var $btn = document.getElementById('btn');
    try {
        $btn.onclick = function () {
            console.log(rrr);
        };
    } catch (e) {
        console.log('error');
    }
有效示例:
    var $btn = document.getElementById('btn');
        $btn.onclick = function () {
            try {
                console.log(rrr);
            } catch (e) {
                console.log('error');
            }
        };

表单

1、.value方式可以应用于text、password、hidden以及select的值。

<input type="text" id="form">
var input = document.getElementById('form');
input.value;

2、checked用于单选框和复选框的是否“勾上了”的选项,value属性返回的永远是HTML预设的值。

// html:

     <label><input type="radio" name="relate" id="first">选择一</label>
     <label><input type="radio" name="relate" id="second"> 选择二</label>
     <div id="cli">点击</div>
// js:
    var first = document.getElementById('first');
    var second = document.getElementById('second');
    var cli = document.getElementById('cli');
    cli.onclick = function () {
        console.log(first.checked); // true or false
        console.log(second.checked); // true or false
    }

没有name属性的的数据不会被提交。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值