1、Javascript中null和undefined的区别
总所周知:null == undefined //true
null !== undefined //false
null:是JavaScript的关键字,用于描述“空值”,对其执行typeof操作返回“object”,即为一个特殊的对象值,可以表示数字、字符串和对象是“无值”。
null参与数值运算时其值会自动转换为0,因此,下列表达式计算后会得到正确的数值。
123 + null //123
123 * null // 0
undefined:是预定义的全局变量,其值为“未定义”,typeof(undefined)返回“undefined”,它是变量的一种取值,表示变量没有初始化。当查询对象属性、数组元素的值时,如果返回undefined则表示属性或者元素不存在;如果函数没有任何返回值,也返回“undefined”
alert('undefined' in window);//输出:true
var obj= {};
alert('undefined' in obj); //输出:false
由上可知:undefined是window对象中的一个属性,但不属于object对象。
注意:undefined有特殊的含义,但却不是JavaScript的保留字。
undefined参与任何数组计算时,其结果一定是NaN(Not a number);
By the way: NaN是全局对象的另一个特殊属性,Infinity也是,这行特殊属性都不是JavaScript的保留字!
null == 0; // <span style="color:#cc0000;">false </span>
undefined == ""; // <span style="color:#cc0000;">false </span>
null == false; //<span style="color:#cc0000;"> false </span>
undefined == false; // <span style="color:#cc0000;">false</span>
null == undefined; // <span style="color:#cc0000;">true</span>
2、对象声明提前的思考:
如下代码:
var a = 0;
function a(){};
console.log(a); // 0
function a(){};
var a = 0;
console.log(a); // 0
function a(){};
var a;
console.log(a); //function a() {};
var a;
function a(){}
console.log(a); //function a() {};
注意:函数的声明提前是整个提前,var的提前只是变量的提前,赋值位置不变,由此第一个JS解析器会解析为:
var a;
function a(){};
a = 0;
console.log(a); //0
js中共有五种基础数据类型:Null、Undefined、String、Number、Boolean
原始类型和引用类型有着根本的区别。
原始类型的值是不可更改的,引用类型的值是赋值的引用是可变的:
var a = [1,2];
var b = a;
b.push(3);
console.log(a);//[1,2,3]
上面就是引用类型的理解,var b = a;其实是把a值得引用交给b,这时候他们共享同一个引用,如果对b进行修改则a也会受影响。
4、如何判断是否为数组:
function isArray(data){
if(Array.isArray){//如果存在ES5方法isArray直接调用
return Array.isArray(data);
}else{
return Object.prototype.toString.call(data) === "[object Array]";
}
}
具体详解: http://blog.csdn.net/u013084331/article/details/51150387
5、如何将伪数组转为数组:
无法直接调用数组方法或期望length属性有什么特殊的行为,但仍可以对真正数组遍历方法来遍历它们。典型的是函数的 arguments 参数,还有像调用getElementsByTagName,document.childNodes之类的,它们都返回 NodeList对象都属于伪数组。可以使用Array.prototype.slice.call(fakeArray)将数组转化为真正的Array 对象;
总结:类数组A,A.length能正常返回长度,但不能进行a.push(1)!
var toArray = function(s){
try{
return Array.prototype.slice.call(s);
} catch(e){
var arr = [];
for(var i = 0,len = s.length; i < len; i++){
//arr.push(s[i]);
arr[i] = s[i]; //据说这样比push快
}
return arr;
}
具体详解:
http://blog.csdn.net/u013084331/article/details/51210444
6、数组去重:
一个数组中的去重
function noRepeat(arr){
var result = [];
result[0] = arr[0];
for(var i=1,len=arr.length;i<len;i++){
if(result.indexOf(arr[i]) == -1){
result.push(arr[i]);
}
}
return result;
}
var a1 = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5];
console.log(noRepeat(a1)); //[1,2,3,4,5]
两个数组去重(一个数组去除另一数组已存在的值)
function noRepeatFilter(arr1,arr2){
return arr1.filter(function(arr1Value){
return arr2.indexOf(arr1Value) == -1;
})
}
var a1 = [1,2,3,4,5];
var a2 = [3,4,5,6,7];
console.log(noRepeatFilter(a1,a2));//[1, 2]
7、定义一个log方法,让它可以代理console.log的方法:
方法一:
function log(msg) {
console.log(msg);
}
log("hello world!") // hello world!
方法二:
function log(){
console.log.apply(console, arguments);
};
对于apply和call两者在作用上是相同的,即是调用一个对象的一个方法,以另一个对象替换当前对象。将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
但两者在参数上有区别的。对于第一个参数意义都一样,但对第二个参数: apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入, 而call则作为call的参数传入(从第二个参数开始)。 如 func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1, [var1,var2,var3]) 。
9、原生JS的window.onload与Jquery的$(document).ready(function(){})有什么不同?如何用原生JS实现Jq的ready方法?
window.onload()方法是必须等到页面内包括图片的所有元素加载完毕后才能执行。
$(document).ready()是DOM结构绘制完毕后就执行,不必等到加载完毕。
所以JQ的ready执行比onload要快
原生JS实现JQ的ready方法一:
/* 方法一
* 传递函数给whenReady()
* 当文档解析完毕且为操作准备就绪时,函数作为document的方法调用
*/
var whenReady = (function() { //这个函数返回whenReady()函数
var funcs = []; //当获得事件时,要运行的函数
var ready = false; //当触发事件处理程序时,切换为true
//当文档就绪时,调用事件处理程序
function handler(e) {
if(ready) return; //确保事件处理程序只完整运行一次
//如果发生onreadystatechange事件,但其状态不是complete的话,那么文档尚未准备好
if(e.type === 'onreadystatechange' && document.readyState !== 'complete') {
return;
}
//运行所有注册函数
//注意每次都要计算funcs.length
//以防这些函数的调用可能会导致注册更多的函数
for(var i=0; i<funcs.length; i++) {
funcs[i].call(document);
}
//事件处理函数完整执行,切换ready状态, 并移除所有函数
ready = true;
funcs = null;
}
//为接收到的任何事件注册处理程序
if(document.addEventListener) {
document.addEventListener('DOMContentLoaded', handler, false);
document.addEventListener('readystatechange', handler, false); //IE9+
window.addEventListener('load', handler, false);
}else if(document.attachEvent) {
document.attachEvent('onreadystatechange', handler);
window.attachEvent('onload', handler);
}
//返回whenReady()函数
return function whenReady(fn) {
if(ready) { fn.call(document); }
else { funcs.push(fn); }
}
})();
方法二:
function ready(fn){
if(document.addEventListener) { //标准浏览器
document.addEventListener('DOMContentLoaded', function() {
//注销事件, 避免反复触发
document.removeEventListener('DOMContentLoaded',arguments.callee, false);
fn(); //执行函数
}, false);
}else if(document.attachEvent) { //IE
document.attachEvent('onreadystatechange', function() {
if(document.readyState == 'complete') {
document.detachEvent('onreadystatechange', arguments.callee);
fn(); //函数执行
}
});
}
};
10、实现一个函数clone,可以对JavaScript中的5种主要的数据类型(包括Number、String、Object、Array、Boolean)进行值复制
方法一:
Object.prototype.clone = function(){
var o = this.constructor === Array ? [] : {};
for(var e in this){
o[e] = typeof this[e] === "object" ? <span style="color:#cc0000;">this[e].clone()</span> : this[e];
}
return o;
}
方法二:使用argument.callee
Object.prototype.clone = function(){
var o = this.constructor === Array ? [] : {};
for(var e in this){
o[e] = typeof this[e] === "object" ? arguments.callee(this[e]) : this[e];
}
return o;
}
方法三:
function clone(Obj) {
var buf;
if (Obj instanceof Array) {
buf = []; //创建一个空的数组
var i = Obj.length;
while (i--) {
buf[i] = clone(Obj[i]);
}
return buf;
}else if (Obj instanceof Object){
buf = {}; //创建一个空对象
for (var k in Obj) { //为这个对象添加新的属性
buf[k] = clone(Obj[k]);
}
return buf;
}else{ //普通变量直接赋值
return Obj;
}
}
//2016.4.22未完待续