##js的拖拽
在拖拽时容易使操作变成选择文本,这时应该添加这段:
$("#ul").on("selectstart", "li", function(e){ this.dragDrop && this.dragDrop(); return false;});
##js的event对象
先看的代码:
//获取event对象//标准DOM方法事件处理函数第一个参数是event对象//IE可以使用全局变量window.eventvar 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为null
target, originalTarget, srcElement:触发事件原始的DOM
##jQuery.ready, DOMContentLoaded, window.onload区别
先看jQuery.ready,查看jquery-1.11.3.js
源代码:
// 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:15if ( 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和图片加载完毕,就可以执行一些方法
window.onload则必须等到页面内包括图片(图片也加载完成,img.complete===true时)的所有元素加载完毕后才能执行
##javascript三种设置访问器属性的方式
详情:
另一小小的知识点:普通类型变量给它定义属性没用
##针对retina的支持
// 优化retina, 在retina下这个值是2var 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 = 1function 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
更灵活。
[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 -> truefalse == "0" -> truenull == 0 -> false+null === 0 -> truenull <= 0 -> truenull < 1 -> true'' == 0 -> true // ''会被转换为数字, 相当于+'' == 0'' == false -> true[] == false -> true[] == '' -> truetrue == 1 -> truetrue == 2 -> false'5' == 5 -> trueisNaN('123') -> falseisNaN(null) -> falseNumber([]) === 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 trueconsole.log("count",f.hasOwnProperty("count")); // count falseconsole.log(Foo.prototype.hasOwnProperty("count")); // trueconsole.log(Foo.prototype.hasOwnProperty("get")); // truef.age // -> 25f.count // -> 100,虽然不是f的ownProperty,但直接读取该属性也是可以的console.log(Foo.prototype.isPrototypeOf(f)); // -> trueconsole.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只有函数作用域和全局作用域。作用域链就是从内部函数作用域到外部函数作用域,一直到全局作用域。闭包是简单来说是函数中使用函数,内部函数使用到外部函数的变量,而外部函数之外的作用域对外部函数的返回值有引用,那么外部函数就成了一个闭包,内部函数对外部函数的引用链就不会销毁。
闭包意味着内层的函数可以引用存在于包围它的函数内的变量,即使外层函数的执行已经终止
闭包主要的应用场景以及一些特点有:
- 实现私有变量
var obj = (function(){ var privateVar; return { get: function(){ return privateVar; }, set: function(value){ privateVar = value } };})();
- 闭包传参,保护全局作用域
(function($, undefined){/*…*/})(jQuery)
- 循环中使用闭包,但不声明变量
但闭包有在for/next循环中使用闭包却不声明变量来保存迭代变量当前值的一些风险。闭包允许你引用父函数中的变量,但提供的值并非该变量创建时的值,而是在父函数范围内的最终值。
- 参数和变量不会被垃圾回收机制回收
在函数A内定义一个函数B,B对A中的一些变量有引用,那么A即使运行结束,B对A变量的引用链也不会销毁。所以闭包不能滥用!
##垃圾回收机制 ##循环引用
- 标记清除
在函数中声明一个变量,则将其标记为「进入环境」,当变量离开环境时,则将其标记为“离开环境”。
垃圾回收器在运行的时候会给存储在内存中的所有变量都加上标记(当然,可以使用任何标记方式)。然后,它会去掉环境中的变量以及被环境中的变量引用的变量的标记(闭包)。然后销毁那些带标记的值并回收它们所占用的内存空间
- 引用计数
引用计数的含义是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型值赋给该变量时,则这个值的引用次数就是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;