《javascript高级程序设计》笔记(二十二)

高级技巧

(一)高级函数

1.安全的类型检测

javascript内置的类型检测机制并非完全可靠,如typeof操作符。instanceof操作符在存在多个全局作用域(一个页面包含多个iframe)时会有问题。

//value要是一个数组,且与Array构造函数在同一个全局作用域
//如果value是另个iframe的数组,则返回false
var isArray = value isinstanceof Array;

原生数组的构造函数名与全局作用域无关,使用toString()能保持返回一致的值。

//检测某个值是不是数组
function isArray(value){
  return Object.Prototype.toString.call(value) == "object Array";
}

//检测某个值是不是函数
function isFunction(value){
  return Object.Prototype.toString.call(value) == "object Function";
}

//检测某个值是不是正则表达式
function RegExp(value){
  return Object.Prototype.toString.call(value) == "object RegExp";
}

//检测某个值是不是原生JSON
var isNativeJSON = window.JSON && Object.prototype.toString.call(JSON) == "object JSON";

Object的toSting()方法不能检测非原生构造函数的构造函数名,返回[object Object]。

2.作用域安全的构造函数

当使用new调用时,构造函数内用的this对象会指向新创建的对象实例。

        var person1 = new Person("Nicholas", 29, "Software Engineer");
        alert(person1.name);     //"Nicholas"

        var person2 = Person("Nicholas", 29, "Software Engineer");
        alert(person2);         //undefined
        alert(window.name);     //"Nicholas"

当没有使用new操作符来调用该构造函数的情况时,由于该this对象是在运行时绑定的,所以直接调用Person (),this会映射到全局对象window。

原本对Person实例的属性被加到window对象,因为构造函数作为普通函数调用,忽略了new操作符。

作用域安全的构造函数,在进行任何修改前,先确定this对象是正确类型的实例,不是就创建新的实例并返回。

        function Person(name, age, job){
            if (this instanceof Person){
                this.name = name;
                this.age = age;
                this.job = job;
            } else {
                return new Person(name, age, job);
            }
        }

如果使用构造函数窃取模式的继承而不使用原型链,这个继承会被破坏。

        function Rectangle(width, height){
            Polygon.call(this, 2);
            this.width = width;
            this.height = height;
            this.getArea = function(){
                return this.width * this.height;
            };
        }

因为Polygon的构造函数是作用域安全的,this对象并非Polygon的实例,所以会创建并返回一个新的对象。Rectangle实例没有sides属性。

构造函数窃取结合使用原型链或寄生组合可以解决。

3.惰性载入函数

惰性载入表示函数执行的分支仅会执行一次

方法一:在函数被调用时再处理函数,在第一次调用的过程中,该函数会被覆盖为另一个按合适方式执行的函数,任何对原函数的调用都不再经过执行的分支了。

方法二:在声明函数时就指定适当的函数。

优点:只在执行分支代码时牺牲一点系能。

4.函数绑定

在特定的this环境指定函数调用另一个函数。这技巧常常和回调函数与事件处理程序一起用,以便在将函数作为变量传递的同时保留代码执行环境。

bind()函数接收一个函数和一个环境,并返回一个在给定环境中调用给定函数的寒素,将所有参数原封传递过去。

        function bind(fn, context){
            return function(){
                return fn.apply(context, arguments);
            };
        }

支持原生bind()方法  IE9+  Firefox 4+  Chrome

主要用于事件处理程序和setTimeout()和setInterval()。

5.函数柯里化

用于创建已经设置好了一个或多个参数的函数。使用一个闭包返回一个函数,当函数被调用时,返回的函数还要设置一些传入的参数。

创建:调用另一个函数并未它传入要柯里化的函数和必要参数。

        function curry(fn){
            var args = Array.prototype.slice.call(arguments, 1);
            return function(){
                var innerArgs = Array.prototype.slice.call(arguments),
                    finalArgs = args.concat(innerArgs);
                return fn.apply(null, finalArgs);
            };
        }

(二)防篡改对象

一旦把对象定义为防篡改,就无法取消。

1.不可扩展对象

Object.preventExtensions()方法,不能再给对象添加属性和方法,仍然可以修改和删除已有成员。

Object.inExtensible():确定对象是否可以扩展。

2.密封的对象

不可扩展,而且已有成员的[[Configurable]]特性被修改为false,不能删除属性和方法,但可以修改。

使用Object.seal()方法。

Object.isSealed() 检测是否被密封。

3.冻结的对象

不可扩展、密封而且对象数据的[[Writable]]特性被设置为false。

Object.freeze()

Object.isFrozen()方法  检测

(三)高级定时器

页面载入时,先值任何包含在<script>的代码,通常是页面生命周期后面要用的简单的函数和变量的声明。

1.重复的定时器

链式setTimeout()

setTimeout ( function)(){

          //处理中

          setTimeout(arguement.callee,interval);

}, interval);

在前一个定时器执行完之前,不会向队列插入新的定时器代码,确保不会有缺失的间隔,避免了连续的运行。主要用于重复计时器。

        setTimeout(function(){

           var div = document.getElementById("myDiv"),
               left = parseInt(div.style.left) + 5;
           div.style.left = left + "px";

           if (left < 200){
               setTimeout(arguments.callee, 50);
           }

        }, 50);

2.Yielding Progresses

脚本长时间运行通常由两个原因造成:过长的、过深嵌套的函数调用或者进行大量处理的循环。后者是比较容易解决的问题。

数组分块:为要处理的项目创建一个队列,然后使用定时器取出下一个要处理的项目进行处理,接着再设置另一个定时器。

setTimeout(function (){
    //取出下一个条目并处理
    var item = array.shift();
    process(item);

    //若还有条目,再设置另一个定时器
    if(array.length>0){
           setTimeout (arguments.callee, 100);
    }
},  100)
        function chunk(array, process, context){
            setTimeout(function(){
                var item = array.shift();
                process.call(context, item);

                if (array.length > 0){
                    setTimeout(arguments.callee, 100);
                }
            }, 100);
        }

3.函数节流

代码不可以在没有间断的情况下连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。第二次调用时它会清楚前一次的定时器并设置另一个。如果前一个定时器已经执行,则这个操作没有意义。如果未执行,将其代替为新的定时器。目的是只有在执行函数的请求停止了一段时间之后才执行。

var processor = {
      timeoutId: null,

      //实际进行处理的方法
      performProcessing: function(){
            //实际执行的代码
      },

      //初始化进行调用的方法
      process: function(){
               clearTimeout(this.timeoutId);

               var that = this;
               this.timeoutId = setTimeout(function)(){
                    that.performProcessing();
               }, 100);
      }
};

简化,自动进行定时器的设置和清除

        //参数:要执行的函数  在哪个作用域执行        function throttle(method, scope) {
            clearTimeout(method.tId);
            method.tId= setTimeout(function(){
                method.call(scope);
            }, 100);
        }

节流在resize时间最常用。

(四)自定义事件

主体负责发布时间,观察者通过订阅时间来观察主体。主体不知道观察者的任何事,它可以独自存在并正常运作即使观察者不存在。

观察者知道主体并能注册事件的回调函数。

自定义事件:创建一个管理事件的对象,让其他对象监听那些事件。

代码中存在多个部分在特定时刻相互交互的情况下,自定义事件非常有必要、

(五)拖放

基本概念:创建一个绝对定位的元素,使其可以用鼠标移动。

1.修缮拖动功能

计算元素左上角和指针之间的差,这个值在mousedown事件发生时就确定,并一直保持知道mouseup发生。

        var DragDrop = function(){

            var dragging = null,
                diffX = 0,
                diffY = 0;

            function handleEvent(event){

                //获取事件和目标                event = EventUtil.getEvent(event);
                var target = EventUtil.getTarget(event);            

                //确定事件类型
                switch(event.type){
                    case "mousedown":
                        if (target.className.indexOf("draggable") > -1){
                            dragging = target;
                            diffX = event.clientX - target.offsetLeft;
                            diffY = event.clientY - target.offsetTop;
                        }
                        break;

                    case "mousemove":
                        if (dragging !== null){

                            //指定位置
                            dragging.style.left = (event.clientX - diffX) + "px";
                            dragging.style.top = (event.clientY - diffY) + "px";
                        }
                        break;

                    case "mouseup":
                        dragging = null;
                        break;
                }
            };

            //公共接口            return {
                enable: function(){
                    EventUtil.addHandler(document, "mousedown", handleEvent);
                    EventUtil.addHandler(document, "mousemove", handleEvent);
                    EventUtil.addHandler(document, "mouseup", handleEvent);
                },

                disable: function(){
                    EventUtil.removeHandler(document, "mousedown", handleEvent);
                    EventUtil.removeHandler(document, "mousemove", handleEvent);
                    EventUtil.removeHandler(document, "mouseup", handleEvent);
                }
            }
        }();

        DragDrop.enable();

公共方法enable()和disable()只是相应添加和删除所有的事件处理程序,这两个函数提供了额外的对拖放功能的控制手段。

2.添加自定义事件

先创建一个新的EventTarget对象,然后添加enable()和disable()方法,最后返回这个对象。

时间: 2024-10-31 06:24:27

《javascript高级程序设计》笔记(二十二)的相关文章

JavaScript高级程序设计:第十二章

DOM1级主要定义的是HTML和XML文档的底层结构.DOM2和DOM3级则在这个结构的基础上引入了更多的交互能力,也支持了更高级的XML特性.为此DOM2和DOM3级分为许多模块,这些模块如下: DOM2级核心: DOM2级视图: DOM2级事件: DOM2级样式: DOM2级遍历和范围: DOM2级HTML. 一.DOM变化 DOM2级和3级的目的在于扩展DOM API,以满足操作XML的所有需求,同时提供更好的错误处理及特性检测能力. 1.针对XML命名空间的变化 有了XML命名空间,不同

javascript高级程序设计——笔记

javascript高级程序设计--笔记 基本概念 基本数据类型包括Undefined/Null/Boolean/Number和String 无须指定函数的返回值,实际上,未指定返回值的函数返回的是一个特殊的undefined值 变量.作用域和内存问题 基本类型值在内存中占据固定大小的空间,因此保存在栈内存中 引用类型的值是对象,保存在堆内存中 确定一个值是哪种基本类型用typeof,确定一个值是哪种引用用instanceof 所有变量都存在于一个执行环境当中,这个执行环境决定了变量的生命周期,

javascript高级程序设计笔记1

最近在看javascript高级程序设计,看之前觉得自己的js学得还不错,然后,看了没几页就觉得自己好像没有学过一样,这主要写写我以前不完全了解的一些知识. 首先是关于基本数据类型的,从Number开始,以前经常用parseInt来转换数值,看过书才知道,这个函数的本意是专门用于把字符串转换成数值,而且以前也不知道它具体是怎么一个转换规则.先来看看Number()函数的转换规则: 1.如果是Boolean 值,true 和false 将分别被转换为1 和0.2.如果是数字值,只是简单的传入和返回

【javascript高级程序设计笔记】第六章OOP

忙了一段时间,加了将近一个月的班. 书也落下没看,上次看到第七章(这部分笔记大概还是9月份的吧),偶尔看到很吃力.看的速度慢下来. 学习就是一个慢慢积累慢慢沉淀的过程.看书时没有明显觉得提升.但在看完书后近段时间工作中写代码,明显感觉效率还是有提升,基础知识牢固了. 这本书是第二次看,这次很认真的遍读和做笔记,笔记的文字均是自己边看边敲的,这样才更好的真正的吸收到一部分吧! 这些天在看web响应式设计:HTML5和CSS3实战 第6章 面向对像的程序设计 6.1.1属性类型 ECMAScript

JavaScript高级程序设计:第十四章

第十四章 一.表单的基础知识 在HTML中,表单是由<form>元素来表示的,而在javascript中,表单对应的则是HTMLFormElement类型.HTMLFormElement继承了HTMLElement,因而与其他HTML元素具有相同的默认属性.不过,HTMLFormElement也有它自己下列独有的属性和方法. 取得<form>元素的引用方式有好几种.其中最常见的方式就是将它看成与其他元素一样,并为其添加id特性,然后再像下面这样使用getElementById()方

【javascript高级程序设计笔记】第一章与第三章

第1章 javascript简介 1.2Javascript实现 一个完整的javascript实现由下列三个不同的部分组成 核心(ECMAScript) 提供核心语言功能 文档对象模型(DOM) 提供访问和操作网页内容的方法和接口 浏览器对象模型(BOM)提供与浏览器交互的方法和接口 ECMAScript 它规定了这门语言的下列组成部分: 语法  类型  语句  关键字 保留字 操作符 对象 ECMA-262第5版,发布于2009年. 文档对象模型(DOM) Document Object M

javascript高级程序设计笔记(第5章 引用类型)

1.Object类型 两种方式定义:对象字面量.new 两种方式访问:括号.点 2.Array类型 2.1  定义方式:new Array.数组字面量 2.2  lenght属性:可以利用它方便的想数组末尾添加元素 2.3  检测数组 instanceof isArray()方法  2.4  toString().soLocaleString().valueOf().join()方法 2.5.栈方法   push()方法:逐个添加到数组末尾,并返回修改后的数组长度 pop()方法:返回数组的最后

javascript高级程序设计--笔记01

概述 JavaScript的实现包含三个部分: 1  核心(ECMAScript)   提供核心语言功能 2  文档对象模型(DOM)  一套提供了访问以及操作网页内容的API 3  浏览器对象模型(BOM)  一套提供了与浏览器交互的API ECMAScript仅仅定义了这门语言的基础,如定义了:语法.类型.语句.关键字等,实际上这门语言本身不包含输入输出定义. 而现实中,ECMAScript大多借用了某些宿主环境(如web浏览器,Node,Adobe Flash)来实现丰富的功能,这些宿主环

javascript事件小结(事件处理程序方式)--javascript高级程序设计笔记

1.事件流:描述的是从页面中接收事件的顺序. 2.事件冒泡:IE的事件流叫做事件冒泡,即事件开始从具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到不具体的节点(文档). 3.事件捕获:指不太具体的节点应该更早接收到事件,而具体的节点应该是最后接收到事件. 4.DOM事件流:“DOM2级事件”规定的事件流包含三个阶段:事件捕获,处于目标阶段和事件冒泡阶段.(实际的目标元素在捕获阶段接不会收到事件) IE不支持DOM事件流,Opera.safari.chrome.firefox支持

JavaScript高级程序设计笔记(一)

1. ECMA规定了这门语言的下列组成部分: 语法. 类型.语句. 关键字.保留字.操作符. 对象 2. 什么是 ECMAScript 兼容支持 ECMA描述的所有"类型.值.对象.属性.函数以及程序句法和语义"支持 Unicode 字符标准. 此外,兼容的实现还可以进行下列扩展.添加 ECMA没有描述的"更多类型.值.对象.属性和函数".支持 ECMA没有定义的"程序和正则表达式语法". 3. 5种简单数据类型: Undefined(不明确的,