Javascript 深入了解Javascript 基础知识

原创 2014年08月26日 16:45:37

eval全局函数

dojo 的加载器中会看到以下一个函数
   var eval_ = new Function('return eval(arguments[0]);'); //Function 函数是在顶级作用域下运行, 但运行效率更慢, 但使用这种方法不会污染全局变量,并且调用的是顶级作用域
    eval('var i =100;');
    alert(i); // 100
    eval_('var b = 100');
    //alert(b); //错误, b 没有定义




    var where = '我在国外'; //全局作用域的where
    function test() {
        var where = '我在国内'; //闭包的where
        eval_('alert(where)'); //我在国外, 全局作用域
        eval('alert(where)');//我在国内, 局部全用域
        window.eval('alert(where)'); //我在国外 IE6/7/8 我在国内,不会采用全局作用域, 可以使用execScript
    }
    test()

dojo的kernal模块中也会有一个eval函数, 代码和解释如下 

(Function("d", "d.eval = function(){return d.global.eval ? d.global.eval(arguments[0]) : eval(arguments[0]);}"))(dojo);
	/*=====
	dojo.eval = function(scriptText){

		//  尝试在全局作用域下执行角本字符串(scriptText), 除了IE不能支持,其它浏览器都可以正确的在全局作用域下执行, IE下执行
		    dojo.eval('var pi = 3.14');
		    alert(pi)  //pi undefined;
            要在IE中执行全局变量
            dojo.eval("window.pi = 3.14");
            
		    IE 下要执行全局变量, 只能使用execScript, 但是它不会返回值, 并且不能终止执行
	*/
	

对像的属性检测与枚举

Javascript 对于有以下几个方法用于属性的检测

  • in 操作符 , 如果对象的自有属性或者继承属性有包含被检测的属性, 则返回ture, "toString" in { x: 'hello'} //true;
  • hasOwnProperty() 检测给定的名字是否为对像的自有属性,如果是,返回true, 对于继承属性,返回false;
  • propertyIsEnumerable() 是hasOwnProperty的增强版, 检测自有属性, 并且可枚举
  • for/in 枚举对像的属性的可枚举属性包括(自有属性和继承属性),不枚举内置方法("toString" ), 但自已重写的内置方法,可被枚举
  • toString, toLocaleString, valueOf 等内置属性不可枚举, Object.prototype.propertyIsEnumerable('toString') 返回true, 但对于代码定义的toString方法,是可枚举的(大部分自已定义的属性都可枚举), 但在IE6之前,自已重新定义的内置方法,还是不可枚举. 可以通过以下代码进行调整
 /*
       定义一个扩展函数,用来将第二个以及之后的参数, 复制到第一个参数
       但在IE下,有一个bug, 就是对于自已定义的内置方法(如在第二个参数对像里有定义toString方法, 那么IE6下for/in不会枚举到toString方法,也就不会复制这个自定义方法
       所以在代码的里需要显示的检测它
       多个对像时,参数右则的属性等级更高
     */
        var extend = (function(){

            for(var p in {toString:null}){
                return function(o){
                    for(var i = 1, len = arguments.length; i < len; i++){
                        var source = arguments[i];
                        for(var prop in source) o[prop] = source[prop];
                    }
                    return o;
                }
            }
            // IE 6
            var protoprops = ['toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'isPrototypeOf', 'constructor', 'propertyIsEnumerable'];
            return function(o){
                for(var i = 1, len = arguments.length; i < len; i++){
                    var source = arguments[i];
                    for(var prop in source) o[prop] = source[prop];
                    for(var j = 0; j < protoprops.legnth; j++){
                        prop = protoprops[j];
                        if(source.hasOwnProperty(prop)) o[prop] = source[prop];
                    }
                }
                return o;
            }

        })()

isString 等方法的实现

/*
        著名大师 Douglas Crockford 的实现方法
        但对于 instaceof 有一个局限, instaceof 在两个页面,如A 页面定义了isString方法, 那么能过<iframe name='bPage'> 框架,加载的 B 页面,并定义 var test = new String('test')
        window.onload = function(){
            isString(window.bPage.test); // false;
        }
     */
    function isString(i){
        return typeof i === 'string' || i instanceof String;  // instanceof 用于检测 new String() 创建的字符串
    }
    /*
        有一个小缺点:如果其它的库重新定义了继承的String类,那么会返回 [object Object], 而上面的方法可以检测到这个是一字符串
     */
    function isString(i){
        return {}.toString.call(i) === "[object String]";
    }

toArray 方法的实现, IE8 下有区别

toArray 方法主要将类数组对像(arguments, NodeList) 变为数组对像, 但在IE8及以下,不能将html元素转变为Javascript对像,所以会报错

 efficient = function(obj, offset, startWith){
        console.log('efficient');
        return (startWith || []).concat(Array.prototype.slice.call(obj, offset||0))
    }
    _toArray = parseInt(window.navigator.appVersion.split('MSIE ')[1]) <= 8 ?
            (function(){
                function slow(obj, offset, startWith){
                    var arr = startWith||[];
                    for(var x = offset || 0; x < obj.length; x++){
                        arr.push(obj[x]);
                    }
                    return arr;
                }
                return function(obj){
                    return ((obj.item) ? slow : efficient).apply(this, arguments);  //如果只决断是否为IE, has(ie), 那么IE9以上的浏览器也会调用slow方法,效率就慢了
                };
            })() : efficient
       window.onload = function(){

           var input = document.getElementsByTagName('input')

           _toArray(input)[0].value = '12'; //IE8及以下的浏览器, 不支持obj对像为非javascript对像
       }

for 循环里的 i++ 与 ++i

这两种写法的效果是一样的,但i++在使用时,会创建一个地址来保存i原来的,增加内存,而++i是直接增加 i 的值, 所有最好使用 for(var i=0; i < 100; ++i) , 源代码来自 dojo/_base/array.js

异或(^)的使用

用于every 和 some的判断, 源代码来自dojo/_base/array.js
function everyOrSome(some){
		var every = !some;
		return function(a, fn, o){
			var i = 0, l = a && a.length || 0, result;
			if(l && typeof a == "string") a = a.split("");
			if(typeof fn == "string") fn = cache[fn] || buildFn(fn);
			if(o){
				for(; i < l; ++i){
					result = !fn.call(o, a[i], i, a);  //一定要加!运算符,转换为boolean类型
					if(some ^ result){<span style="white-space:pre">	</span>//some 设置为true, 当遇到一个false时,直接返回true; every 即some取反, every = false, 当遇到fn计算结果为false, 取反后为 true, 那么 false ^ true 为 true, 那么返回 !true.
						return !result;
					}
				}
			}else{
				for(; i < l; ++i){
					result = !fn(a[i], i, a);
					if(some ^ result){
						return !result;
					}
				}
			}
			return every; // Boolean
		};
	}


数组length的相关问题

学习dojo/quers.js源代码中,需要检测是否可以扩展数组, 如果是老的浏览器(IE6, 7), 则不能对数组进行扩展. 如果可以扩展数组,那么可以将NodeList 类的原型设定为[], 否则为{}.


function A(){}
A.prototype=new Array();
var a=new A();
m.push('a','b','c');
alert(a);//IE6 7:0 其他:3
alert(a[2]);//所有浏览器:'c', 当使用原型继承数组时,IE 6 7下length会始终为0,无论你有多少个元素,其他浏览器则正常。


选择器的兼容性


getElementById, getElementsByTagName 所有浏览器支持 
getElementsByClassName IE8及以下不支持
querySelectorAll, IE7及以下不支持 

对querySelectorAll的思考

<div><p id="foo"><span><i><i></span></p></div>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.0/dojo/dojo.js"></script>
<script>
    var foo = document.getElementById("foo");
    // should return nothing
    alert( dojo.query('div span', foo).length ); //0
    // will return the SPAN (booo!)
    alert( foo.querySelectorAll('body div span').length );  // 1
</script>

IE8 及以上浏览器都支持 querySelectorAll方法, 但是在元素上调用时,指定的选择器仍然在整个文档中进行匹配, 然后过滤出结果集,以便结果集只包含指定元素的后代元素, 也就是说你可以指定"body div span" 选择器字符串,字符串可以包含元素的祖先,而不仅仅是 span.

这样会导致使用时不够直观, 而且跟平常库的使用方式也不一样

    // jQuery
      $("#foo").find("> span");
     
      // DOM  document.getElementById("foo").querySelectorAll(">span") 不支持 >span 这种css选择符
      document.getElementById("foo").querySelectorAll(":root > span") //需要配合:root等于 div#foo, 而不是document element

错误的处理

	

    var selector = "div:foo";
      try {
        document.querySelectorAll(selector);
      } catch(e) {
        alert(selector.slice(e.position)); // ":foo"
      }

如果指定选择符有问题, querySelectorAll 会报错, 所以必须经过 try{}catch(e){} 处理

dojo 中在使用querySelectorAll 时, 会构建一个零时 id, 然后从 foo的上级中查找 foo.querySelectorAll("span i"), 会等于 div.querySelectorAll("[id='foo'] span i");

getAttribute


getAttribute 的性能要比 element.id, element.src 等效率上要低,但比getAttributeNode的性能要高。 对于IE7 等老版的浏览器, 不能获得placeholder, 而attributes['placeholder'] 或者 getAttributeNode('placeholder').nodeValue 可以获得.  

注意: DOJO 的 dom-attr.js 没有修复这个bug, 而jQuery是正常的可以返回 placeholder的值

offsetLeft bug 问题

IE8 中offsetLeft 和 offsetTop 会包含父元素border的宽度, 而其它浏览器则没有。 而且在dojo的解决方案是减去父元素的border值,如果在定位元素中单多了一个div容器(border:0), 那么减去的是0, 而不是最外层容器的border 5px;

scrollLeft 问题

在使用scrollLeft 获取滚动条的位置时,需要考虑 dir="rtl" 时,文档从右向左, 滚动条向右移动时,IE返回正值(IE8及以上,是相对于浏览器右端的值,而IE7是相对于左端的值),而其它浏览器是负值, 在现实代码中不用考虑这种情况,但在阿拉伯语的网页中,需要考虑

document.body

在dojo/_base/window.js 中有一个 body(document)方法,我们平时可以直接使用document.body来调用,但是在xhtml中,不能使用这种方法,只能使用document.getElementsByTagName('body')[0]

parentWindow 与 defaultView

parentWindow 是IE特有的属性, 通过document.parentWindow 或者 document.defaultView 获得文档所在的Window对像。在dojo的dom-geometry的docScroll获取滚动条位置(可能是窗口滚动条,也可能是frame的滚动条),所以需要根据传入的document来获得Window对像.

innerText  与 innerHTML

dojo-prop 中设置元素的文本时,会调用textContent, 而不会调用 innerText, 而是创建一个createTextNode('value'), 原因如下 http://msdn.microsoft.com/en-us/library/ms533899%28v=VS.85%29.aspx

1. innerText  只在block element 中有效,如果你在<hr>元素上调用,会报错

2. 对于 html, table, tBody, tFoot, tHead, and tr, innerText & innerHTML 是只读属性

还需要注意一个问题, 在清除元素的子节点时,通常会使用 removeChild() 方法, 但是removeChild在IE中会导致内存泄漏, 所以可以使用 innerHTML = "" ;



版权声明:本文为博主原创文章,未经博主允许不得转载。

javascript基础知识总结

  • 2012年11月28日 14:06
  • 45KB
  • 下载

Javascript基础知识

  • 2015年11月17日 21:35
  • 59KB
  • 下载

源码-JavaScript&jQuery交互式前端开发-第1章-编程基础知识

示例:根据当前时间,显示不同的问候语 示例效果: JS代码如下: var today = new Date(); var hourNow = today.getHours(); va...

HTML和javascript的基础知识

  • 2011年04月02日 16:53
  • 14.1MB
  • 下载

javascript基础知识大全

  • 2012年08月03日 10:15
  • 37KB
  • 下载

HTML5学习笔记 —— JavaScript基础知识

来源于我的HTML5学习笔记,通过它可以快速入门HTML5,同时可以作为工作中快速查找知识点的利器。 本文由浅入深地详解了JavaScript的各项基础知识点,通过本文你将会对JavaScript语...

PHP-Javascript基础知识

  • 2011年12月16日 13:51
  • 295KB
  • 下载

说说 JavaScript 表单脚本之基础知识

HTML 中,使用 来表示表单元素;在 JavaScript 中,使用的是 HTMLFormElement 类型,它继承自 HTMLElement,所以它有继承了来的一些属性,除此之外,还有一些独有...

Javascript基础知识

  • 2017年01月04日 19:29
  • 365KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Javascript 深入了解Javascript 基础知识
举报原因:
原因补充:

(最多只允许输入30个字)