JavaScript实用手册

##js的拖拽javascript

在拖拽时容易使操做变成选择文本,这时应该添加这段:html

$("#ul").on("selectstart", "li", function(e){
  this.dragDrop && this.dragDrop();
  return false;
});

##js的event对象前端

先看文章的代码:java

//获取event对象
//标准DOM方法事件处理函数第一个参数是event对象
//IE可使用全局变量window.event
var evt = window.event?window.event:e;

//获取触发事件的原始事件源
//标准DOM方法是用target获取当前事件源
//IE使用evt.srcElement获取事件源
var target = evt.target||evt.srcElement;

//获取当前正在处理的事件源
//标准DOM方法是用currentTarget获取当前事件源
//IE中的this指向当前处理的事件源
var currentTarget= e?e.currentTarget:this;

//问题:在IE 9下  window.event 与 e 不一样 evt没有currentTarget属性,e才有currentTarget属性(视为标准浏览器作法??)
alert("src id:"+target.id+"\ncurent target id :"+currentTarget.id);

currentTarget:事件冒泡阶段所在的DOM。在捕获事件时,这个currentTarget就为监听事件的那个DOM元素,当事件结束时,currentTarget为nulljquery

target, originalTarget, srcElement:触发事件原始的DOMgit

##jQuery.ready, DOMContentLoaded, window.onload区别github

先看jQuery.ready,查看jquery-1.11.3.js源代码:ajax

// Catch cases where $(document).ready() is called after the browser event has already occurred.
// we once tried to use readyState "interactive" here, but it caused issues like the one
// discovered by ChrisS here: http://bugs.jquery.com/ticket/12282#comment:15
if ( document.readyState === "complete" ) {
  // Handle it asynchronously to allow scripts the opportunity to delay ready
  setTimeout( jQuery.ready );

// Standards-based browsers support DOMContentLoaded
} else if ( document.addEventListener ) {
  // Use the handy event callback
  document.addEventListener( "DOMContentLoaded", completed, false );

  // A fallback to window.onload, that will always work
  window.addEventListener( "load", completed, false );

// If IE event model is used
} else {
  // Ensure firing before onload, maybe late but safe also for iframes
  document.attachEvent( "onreadystatechange", completed );

  // A fallback to window.onload, that will always work
  window.attachEvent( "onload", completed );
......

可看出jQuery也是主要利用DOMContentLoaded事件编程

DOMContentLoaded是在DOM结构绘制完毕后就执行,不必定要等全部的js和图片加载完毕,就能够执行一些方法json

window.onload则必须等到页面内包括图片(图片也加载完成,img.complete===true时)的全部元素加载完毕后才能执行

##javascript三种设置访问器属性的方式

详情:http://avalonjs.github.io/#tutorial/concepts/vmodel.html

另外一小小的知识点:普通类型变量给它定义属性没用

##针对retina的支持

// 优化retina, 在retina下这个值是2
var ratio = window.devicePixelRatio || 1;

##判断图片是否已加载了

利用complete属性可判断:img.complete

##运算符的优先级

输入图片说明

##visibilitychange事件

标签页激活检测(视觉改变触发):当用户焦点在另一个标签上,或从新回到标签时,触发visibilitychange事件:

$(document).on('visibilitychange', function (e) {
  if (e.target.visibilityState === "visible") {
    console.log('Tab is now in view!');
  } else if (e.target.visibilityState === "hidden") {
    console.log('Tab is now hidden!');
  }
});

##cookies,sessionStorage和localStorage的区别

  • sessionStorage用于本地存储一个会话的数据,这些数据只有在同一会话中的页面才能访问而且会话结束后数据也随之销毁。所以sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。而localStorage用于持久化的本地存储,除非主动删除数据,不然数据是永远不会过时的。
  • cookie的容量小,WebStorage的容量大大提高
  • Cookie的大小是受限的,而且每次你请求一个新的页面的时候Cookie都会被发送过去,这样无形中浪费了带宽
  • cookie还须要指定做用域,不能够跨域调用
  • Web Storage拥有setItem,getItem,removeItem,clear等方法,不像cookie须要前端开发者本身封装setCookie,getCookie
  • 可是Cookie也是不能够或缺的:Cookie的做用是与服务器进行交互,做为HTTP规范的一部分而存在 ,而Web Storage仅仅是为了在本地“存储”数据而生

关于new运算符的一道题

x = 1
function bar(){
    this.x = 2
    return x
}
var foo = new bar()
alert(foo.x) // -> 2

这里主要问题是最外面x的定义,试试把x=1改为x={},结果会不一样的。这是为何呢?

在把函数看成构造器使用的时候,若是手动返回了一个值,要看这个值是否简单类型,若是是,等同于不写返回,若是不是简单类型,获得的就是手动返回的值。若是,不手动写返回值,就会默认从原型建立一个对象用于返回。

##js的script标签的defer和async属性

[defer]

能够在<script>中加入defer属性,告诉浏览器这段script没必要当即执行,那么浏览器就会在彻底载入文档以后再执行这个script,至关于window.onload,但它比window.onload更灵活。

<script defer="true"></script>

[async]

使用async属性加载JavaScript,这样整个脚本就能够异步加载和执行。

<script>标签的defer属性——告诉浏览器该脚本不会在页面加载完成以前操做DOM,脚本将会和其余资源文件并行下载; <script>标签的async属性——HTML5新的异步、并行模式,脚本将在完成下载后等待合适的时机执行代码。

##parseInt,parseFloat

parseInt('0xA')    // return 10`
parseInt('A')      // return NaN`
parseInt('A', 16)  // return 10`
parseFloat('22.22.22') // return 22.22`
parseFloat('A', 16)    // return NaN`,没有基模式
parseFloat('0xA')      // return 0`,不转换为十六进制,直接转前面数字部分而已

void运算符

void运算符对任何值都返回undefined,该运算符经常使用于避免输出不该该输出的值。例如: <a href="javascript:window.open('about:blank');">Click Me</a>

其中,window.open()返回对新打开窗口的引用,会输出字符串的,应该改成: <a href="javascript:void(window.open('about:blank'));">Click Me</a>

不能忽视坑爹弱等号 ==

false == 0 -> true
false == "0" -> true
null == 0 -> false
+null === 0 -> true
null <= 0    -> true
null < 1      -> true
'' == 0 -> true    // ''会被转换为数字, 至关于+'' == 0
'' == false -> true
[] == false -> true
[] == ''  -> true
true == 1 -> true
true == 2 -> false
'5' == 5   -> true
isNaN('123') -> false
isNaN(null) -> false
Number([]) === Number('') === 0

小结:null 只弱等于 undefined , 但Number(null)等于0,0跟false是弱等的,因此 null != false, +null == false

ajax获取数据中文乱码问题

使用scriptCharset便可解决问题,用contentType就不必定能够了。

$.ajax({
  url: testUrl,
  dataType: 'jsonp',
  type: 'post',
  scriptCharset: 'utf-8'
});

##URL的基本概念:URL完整组成部分

输入图片说明

纠正一下:

  • 以上图片中,path参数不包括hash
  • window.location不包括path属性,只有pathname

##window.onload和DOMContentLoaded事件的区别

前者是DOM,图片,样式表,flash等加载完成后触发的,后者是DOM加载完成,但样式表和图片可能未加载完成时就触发的,而且只在某些浏览器中有此事件。

##JavaScript的原型

JavaScript是基于原型的编程语言,当你读取一个对象的属性,JavaScript首先会在本地对象中查找这个属性,若是没找到,JavaScript开始在对象的原型中查找,若仍未找到,还会继续查找原型的原型,直到查找到Object.prototype。若是找到这个属性,则返回这个值,不然返回undefined. 换句话说,若是你给Array.prototype添加了属性,那么全部JavaScript数组都具备了这个属性

##变量提高

变量提高指的是,不管是哪里的变量,都是在一个范围内声明的。JavaScript引擎会将这个声明移到范围的顶部。如:

function foo(){
  // 此处省略若干代码
  var a = 100;
}

运行代码时,实质就是这样:

function foo(){
  var a;
  // 此处省略若干代码
  a = 100;
}

##hasOwnProperty ##isPrototypeOf ##constructor

hasOwnProperty

检查该对象是否有属于它自己的属性/对象,而不是它原型上的属性/对象。由于毕竟那是它原型的属性,而不是它本身的。就等于你能够花你老爸的钱,但毕竟不是你的钱。如:

isPrototypeOf

顾名思义,检查该对象是否为另一对象的原型

constructor

对建立对象的函数的引用(指针),指向的老是一个function

prototype

对该对象原型的引用,返回的是一个object实例

var Foo = function(){
  this.age = 25;
};
Foo.prototype.count = 100;
Foo.prototype.get = function(){return this.count;};

var f = new Foo();
console.log("age",f.hasOwnProperty("age")); // age true
console.log("count",f.hasOwnProperty("count")); // count false
console.log(Foo.prototype.hasOwnProperty("count")); // true
console.log(Foo.prototype.hasOwnProperty("get")); // true
f.age // -> 25
f.count // -> 100,虽然不是f的ownProperty,但直接读取该属性也是能够的

console.log(Foo.prototype.isPrototypeOf(f)); // -> true
console.log(Foo === f.constructor); // -> true

##关于__proto__和prototype的区别

最简单来讲,__proto__属性是实例对象的原型属性,prototype是构造函数的原型属性,二者应该是相等的。如:

function B(){this.name = 'kobe';} B.prototype.age = 20; var b = new B();
alert(b.__proto__ === B.prototype); // true

new构造函数返回的this

当使用new关键字来调用构造函数时,若是构造函数里没有返回任何内容,就会返回this——当前上下文的对象,要否则就返回任意非原始类型的值,如数组,object。如:

var Class1 = function(){return {};}, Class2 = function(){return [];}, Class3 = function(){return function(){};},
Class4 = function(){return 123;},
Person1 = new Class1, // {}
Person2 = new Class2, // []
Person3 = new Class3, // function(){}
Person4 = new Class4; // function instanceof Class4

##栈stack和堆heap的区别

原始值是存储在栈中的简单数据段,也就是说,它们的值直接存储在变量访问的位置;引用值是存储在堆中的对象,也就是说,存储在变量处的值是一个指针,指向存储对象的内存处。若是一个值是引用类型的,那么它的存储空间将从堆中分配。因为引用值的大小会改变,因此不能把它放在栈中,不然会下降变量查寻的速度。相反,放在变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,因此把它存储在栈中对变量性能无任何负面影响。

##Number值集合的外边界:Number.MAX_VALUE和Number.MIN_VALUE

全部ECMAScript数都必须在这两个值之间,不过计算生成的数值结果能够不落在这两个数之间。当计算生成的数大于Number.MAX_VALUE时,它将被赋予值Number.POSITIVE_INFINITY,意味着再也不有数字值,一样,生成的数值小于Number.MIN_VALUE的计算也会被赋予值Number.NEGATIVE_INFINITY,也再也不有数字值。若是返回的是无穷大值,那么结果就不能再用在其余计算。

无穷大的值:Infinity === Number.POSITIVE_INFINITY-Infinity === Number.NEGATIVE_INFINITY,判断是否有穷的isFinite(123) === true

##数字转换为二进制字符串

a=12345, a.toString(2) === "11000000111001",与之相对的是 a = parseInt("11000000111001", 2) === 12345

##闭包(closure) ##做用域链

做用域链:js只有函数做用域和全局做用域。做用域链就是从内部函数做用域到外部函数做用域,一直到全局做用域。闭包是简单来讲是函数中使用函数,内部函数使用到外部函数的变量,而外部函数以外的做用域对外部函数的返回值有引用,那么外部函数就成了一个闭包,内部函数对外部函数的引用链就不会销毁。

闭包意味着内层的函数能够引用存在于包围它的函数内的变量,即便外层函数的执行已经终止

闭包主要的应用场景以及一些特色有:

  1. 实现私有变量
var obj = (function(){
  var privateVar;

  return {
    get: function(){
      return privateVar;
    },
    set: function(value){
      privateVar = value
    }
  };
})();
  1. 闭包传参,保护全局做用域
(function($, undefined){/*…*/})(jQuery)
  1. 循环中使用闭包,但不声明变量

但闭包有在for/next循环中使用闭包却不声明变量来保存迭代变量当前值的一些风险。闭包容许你引用父函数中的变量,但提供的值并不是该变量建立时的值,而是在父函数范围内的最终值。

  1. 参数和变量不会被垃圾回收机制回收

在函数A内定义一个函数B,B对A中的一些变量有引用,那么A即便运行结束,B对A变量的引用链也不会销毁。因此闭包不能滥用!

##垃圾回收机制 ##循环引用

  1. 标记清除

在函数中声明一个变量,则将其标记为「进入环境」,当变量离开环境时,则将其标记为“离开环境”。

垃圾回收器在运行的时候会给存储在内存中的全部变量都加上标记(固然,可使用任何标记方式)。而后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。而后销毁那些带标记的值并回收它们所占用的内存空间

  1. 引用计数

引用计数的含义是跟踪记录每一个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是1。若是同一个值又被赋给另外一个变量,则该值的引用次数加1。相反,若是包含对这个值引用的变量又取得了另一个值,则这个值的引用次数减1。当这个值的引用次数变成0时,则说明没有办法再访问这个值了,于是就能够将其占用的内存空间回收回来。这样,当垃圾回收器下次再运行时,它就会释放那些引用次数为0的值所占用的内存。

Netscape Navigator3是最先使用引用计数策略的浏览器,但很快它就遇到一个严重的问题:循环引用。循环引用指的是对象A中包含一个指向对象B的指针,而对象B中也包含一个指向对象A的引用。

function fn() {
  var a = {};
  var b = {};
  a.pro = b;
  b.pro = a;
}

fn();

以上代码a和b的引用次数都是2,fn()执行完毕后,两个对象都已经离开环境,在标记清除方式下是没有问题的,可是在引用计数策略下,由于a和b的引用次数不为0,因此不会被垃圾回收器回收内存,若是fn函数被大量调用,就会形成内存泄露。

咱们知道,IE中有一部分对象并非原生js对象。例如,其DOM和BOM中的对象就是使用C++以COM对象的形式实现的,而COM对象的垃圾回收机制采用的就是引用计数策略。所以,即便IE的js引擎采用标记清除策略来实现,但js访问的COM对象依然是基于引用计数策略的。换句话说,只要在IE中涉及COM对象,就会存在循环引用的问题。

因此,有时需手动切断JS对象与DOM的链接:

$dom._object = null;
jsObj._dom = null;
相关文章
相关标签/搜索