《JavaScript DOM编程艺术》笔记

做笔记是一个好习惯,做笔记不等于抄书,书上的内容不是一眼就能够看懂的,我们需要将书上的内容做一个“翻译”,翻译成自己一眼就能够读懂的文字。

P23

==与===的区别

var a = false;
var b = '';
a == b;//结果为true
a === b;//结果为false

区别:== 只进行值的比较,而 === 除了判断值相等,还会判断类型是否相等。这里flase和''具有相同的含义,但是它们类型不同,一个是boolean一个是String。

:!= 与 !== 同理

P28

规范:变量用下划线分割各个单词,函数用驼峰命名法。这样便于一眼看出哪些是变量哪些是函数。

变量作用域:在函数内部,用var声明的变量是局部变量,反之则是全局变量。

function square(num) {
  total = num * num;
  return total;
}

var total = 50;
var number = square(20);
alert(total);//答案是400

P42

自己实现一个 getElementsByClassName 方法



    
        
        Shopping list
    
    
        

What to buy

Don't forget to buy this stuff.

  • A tin of beans
  • Cheese
  • Milk

P51

事件处理函数的工作机制:给某个a标签添加onclick事件,onclick双引号里面的js代码返回true或false,如果返回的是true,那么onclick事件处理函数就会认为这个链接被点击了;反之,如果返回false,onclick事件处理函数就会认为这个链接没被点击。

可以通过下面的代码去验证这一结论:

Click me

踩坑

百度

执行完以上代码你会深刻领悟到js 的坑。
首先你要知道 当 onclick 后面的事件不是一个函数名时,它会被包裹到一个匿名函数中执行。
以上就相当于是

obj.onclick = function() {show();}

当点击链接的时候执行 onclick 里面的代码,而不是把show()当作事件处理程序,return false 只是在 show() 这个函数中返回了并没有在 onclick 事件中返回。

因此还会发生跳转

重点在这里:在事件处理函数的工作机制中,当在给某元素添加事件处理函数后,一旦事件发生,相应JavaScript代码就会执行,所调用的JavaScript代码的返回值被传递给事件处理函数。当我们给a标签添加onclick事件处理函数并点击a触发其后,如果相应JavaScript代码返回true,onclick事件处理函数就会认为这个链接被点击了,同样的若返回false即会认为链接未被点击。

所以 可以这样写

百度 
百度

P70

对象检测:检测浏览器是否支持某个方法。

if (!getElementById || !getElementsByTagName) return false;

备注:对象检测是用来向下兼容浏览器的,由于我只是单纯的学习js,所以没必要考虑兼容性的问题。

P72

尽量少访问DOM
只要是查询DOM中的某些元素,浏览器都会搜索整个DOM树。

尽量减少文档中的标记数量
过多不必要的元素只会增加DOM树的规模,进而增加遍历DOM树的时间。

P73

合并js脚本
尽量把多个js脚本合并成一个,这样可以减少加载页面时发送的请求数量。而减少请求数量通常都是在性能优化时首先要考虑的。

用法:在

    标签上添加id="imagegallery",然后再调用prepareGallery()就将图片库初始化成功。

    属性
    placeholder 指定图片展示的位置

    P82

    网页加载完毕的时候执行某个函数

    window.onload = prepareGallery;
    

    执行多条函数

    window.onload = function () {
        firstFunction();
        secondFunction();
    }
    

    这里还有一个弹性最佳的解决方案——不管你打算在页面加载完毕时执行多少个函数,它都可以应付自如。

    function addLoadEvent(func) {
        var oldonload = window.onload;
        if (typeof window.onload != 'function') {
            window.onload = func;
        } else {
            window.onload = function () {
                oldonload();
                func();
            };
        }
    }
    

    如果这个处理函数上还没有绑定任何函数,就像平时那样把新函数添加给它。
    如果这个处理函数上已经绑定了函数,就把新函数追加到现有指令的末尾。

    补充

    typeof:运算符把类型信息当作字符串返回。

    下表总结了 typeof 可能的返回值

    类型 结果
    Undefined 'undefined'
    Null 'object'
    Boolean 'boolean'
    Number 'number'
    String 'string'
    Symbol (ECMAScript 6 新增) 'symbol'
    宿主对象(由JS环境提供) Implementation-dependent
    函数对象 'function'
    任何其他对象 'object'

    示例

    // Numbers
    typeof 37 === 'number';
    typeof 3.14 === 'number';
    typeof Math.LN2 === 'number';
    typeof Infinity === 'number';
    typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写
    typeof Number(1) === 'number'; // 但不要使用这种形式!
    
    // Strings
    typeof "" === 'string';
    typeof "bla" === 'string';
    typeof (typeof 1) === 'string'; // typeof总是返回一个字符串
    typeof String("abc") === 'string'; // 但不要使用这种形式!
    
    // Booleans
    typeof true === 'boolean';
    typeof false === 'boolean';
    typeof Boolean(true) === 'boolean'; // 但不要使用这种形式!
    
    // Symbols
    typeof Symbol() === 'symbol';
    typeof Symbol('foo') === 'symbol';
    typeof Symbol.iterator === 'symbol';
    
    // Undefined
    typeof undefined === 'undefined';
    typeof declaredButUndefinedVariable === 'undefined';
    typeof undeclaredVariable === 'undefined'; 
    
    // Objects
    typeof {a:1} === 'object';
    
    // 使用Array.isArray 或者 Object.prototype.toString.call
    // 区分数组,普通对象
    typeof [1, 2, 4] === 'object';
    
    typeof new Date() === 'object';
    
    // 下面的容易令人迷惑,不要使用!
    typeof new Boolean(true) === 'object';
    typeof new Number(1) === 'object';
    typeof new String("abc") === 'object';
    
    // 函数
    typeof function(){} === 'function';
    typeof class C{} === 'function'
    typeof Math.sin === 'function';
    typeof new Function() === 'function';
    

    null

    typeof null === 'object'; // 从一开始出现JavaScript就是这样的
    

    在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签也成为了 0,typeof null 就错误的返回了'object'

    以上内容从此处摘抄

    判断一个变量是否存在

    这得说一下变量的几种状态(变量的生命周期?)

    a; // 未声明
    var b; // 声明但未赋值(类型为 undefined)
    var c = null; // 赋值(虽然这个值是 null,但其类型为 object)
    

    用 if 语句判断变量是否存在

    if(!a){
        alert("通过")
    }
    if(!b){
        alert("通过")
    }
    if(!c){
        alert("通过")
    }
    

    第一个直接报错,第二、三个都会弹出“通过”,所以 undefinednull 在 if 语句中,都会转换为 false。如果将判断的条件换成一下这样

    if(typeof a != 'undefined'){
        alert("通过")
    }
    if(typeof b != 'undefined'){
        alert("通过")
    }
    if(typeof c != 'undefined'){
        alert("通过")
    }
    

    结果只有第三个弹出“通过”,结论就是 nullundefined 值相同但类型不相同。

    null == undefined // true
    null === undefined // false
    

    P93

    • getElementById
    • getElementsByTagName
    • getAttribute
    • setAttribute

    这些方法都是 DOM Core 的组成部分。它们并不专属于 JavaScript。它们可以用来处理任何一种标记语言(比如 XML)编写的文档。

    P108

    在已有的元素前插入一个新元素
    parentElement.insertBefore(newElement, targetElement);
    我们不必搞清楚父元素到底是哪个,因为 targetElement 元素的 parentNode 属性值就是它。

    var gallery = document.getElementById('imagegallery');
    gallery.parentNode.insertBefore(placeholder, gallery);
    

    将 placeholder 元素插入到 gallery 元素之前

    在已有的元素后插入一个新元素
    没有 insertAfter() 这个方法,我们得自己写一个

    function insertAfter(newElement, targetElement) {
        var parent = targetElement.parentNode;
        if (parent.lastChild == targetElement) {
            parent.appendChild(newElement);
        } else {
            parent.insertBefore(newElement, targetElement.nextSibling);
        }
    }
    

    P115

    XMLHttpRequest对象:Ajax技术的核心。这个对象充当浏览器中的客户端与服务器之间的中间人角色。以往的请求都由浏览器发出,而JavaScript通过这个对象可以自己发送请求,同时也自己处理响应。

    创建 XMLHttpRequest 对象

    IE浏览器(而且不同的版本创建方式也不同)
    var request = new ActiveXObject('Msxml2.XMLHTTP.3.0');
    其他浏览器
    var request = new XMLHttpRequest();

    为了兼容所有浏览器,我们需要一个脚本

    function getHTTPObject() {
        if (typeof XMLHttpRequest == 'undefined') { // IE浏览器
            XMLHttpRequest = function() {
                try {
                    return new ActiveXObject('Msxml2.XMLHTTP.6.0');
                } catch (e) {
                }
                try {
                    return new ActiveXObject('Msxml2.XMLHTTP.3.0');
                } catch (e) {
                }
                try {
                    return new ActiveXObject('Msxml2.XMLHTTP');
                } catch (e) {
                }
                return false;
            }
        }
        return new XMLHttpRequest();
    }
    

    XMLHttpRequest 对象中有许多方法。其中最有用的是 open 方法。

    open(method, url, async)
    作用:初始化 HTTP 请求参数。
    method:指定请求类型,如GET、POST 或 SEND。
    url:请求路径。
    async:是否异步方式发送和请求。

    通过 Ajax 请求本地文件 example.txt

    function getNewContent() {
        var request = getHTTPObject();
        if (request) {
            request.open('GET', 'example.txt', true);
            request.onreadystatechange = function() {
                if (request.readyState == 4) {
                    var para = document.createElement('p');
                    var txt = document.createTextNode(request.responseText);
                    para.appendChild(txt);
                    document.getElementById('new').appendChild(para);
                }
            };
            request.send(null);
        } else {
            alert('Sorry, your browser doesn\'t support XMLHttpRequest');
        }
    }
    

    onreadystatechange 是一个事件处理函数,它会在服务器给 XMLHttpRequest 对象送回响应的时候被触发执行。

    我们给它指定了一个处理函数:
    request.onreadystatechange = doSomething

    注意:在为 onreadystatechange 指定函数引用时,不要在函数名后面加括号。因为加括号标识立即调用函数,并且把函数执行结果赋值给 onreadystatechange,而我们在此只想把函数自生的引用(而不是函数结果)赋值给 onreadystatechange 属性。

    只要 readyState 属性的值变成了4,就可以访问服务器发送回来的数据了。

    访问服务器发送回来的数据:
    responseText 保存文本字符串形式的数据
    responseXML 保存 Content-Type 头部中指定为"text/xml"的数据,其实是一个 DocumentFragment 对象。

    注意:在使用 Ajax 时,千万要注意同源策略。使用 XMLHttpRequest 对象发送的请求只能访问与其所在的 HTML 处于同一个域中的数据,不能向其他域发送请求。还有在谷歌浏览器中使用 Ajax 请求 file:// 协议的文件会报 Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https. 的错误消息,只需右键谷歌浏览器的快捷图标,然后点击属性并且在目标后面添加 --allow-file-access-from-files 就能够解决问题。

    补充

    XMLHttpRequest.send()
    该方法的作用是发送 HTTP 请求。

    一般情况下,使用 Ajax 提交的参数多是些简单的字符串,可以直接使用 GET 方法将要提交的参数写到 open 方法的url参数中,此时send方法的参数为null。如:

    request.open('GET', 'login.jsp?user=XXX&pwd=XXX', true);
    request.send(null);
    

    此外,也可以使用 send 方法传递参数。使用 send 方法传递参数使用的是 POST 方法,需要设定 Content-Type 头信息,模拟 HTTP POST 方法发送一个表单,这样服务器才会知道如何处理上传的内容。参数的提交格式和 GET 方法中 url 的写法一样。设置头信息前必须先调用 open 方法。

    request.open('POST', 'login.jsp', true);
    request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
    request.send('user=' + username + '&pwd=' + password);
    

    readyState 状态说明
    (0)未初始化
    此阶段确认 XMLHttpRequest 对象是否创建,并为调用 open() 方法进行未初始化作好准备。值为0表示对象已经存在,否则浏览器会报错--对象不存在。
    (1)载入
    此阶段对 XMLHttpRequest 对象进行初始化,即调用 open() 方法,根据参数(method,url,true)完成对象状态的设置。并调用 send() 方法开始向服务端发送请求。值为1表示正在向服务端发送请求。
    (2)载入完成
    此阶段接收服务器端的响应数据。但获得的还只是服务端响应的原始数据,并不能直接在客户端使用。值为2表示已经接收完全部响应数据。并为下一阶段对数据解析作好准备。
    (3)交互
    此阶段解析接收到的服务器端响应数据。即根据服务器端响应头部返回的 MIME 类型把数据转换成能通过 responseBody 、responseText 或 responseXML 属性存取的格式,为在客户端调用作好准备。状态3表示正在解析数据。
    (4)完成
    此阶段确认全部数据都已经解析为客户端可用的格式,解析已经完成。值为4表示数据解析完毕,可以通过 XMLHttpRequest 对象的相应属性取得数据。

    概而括之,整个 XMLHttpRequest 对象的生命周期应该包含如下阶段:
    创建-初始化请求-发送请求-接收数据-解析数据-完成

    简化版的 readyState 状态说明
    (0)未初始化:XMLHttpRequest 对象已经创建,但还没有调用 open() 方法。
    (1)载入:已经调用 open() 方法,但尚未调用 send() 方法。
    (2)载入完成:send() 方法已调用。
    (3)交互:服务器正在发送响应。
    (4)完成:服务器完成发送响应。

    DocumentFragment 节点
    DocumentFragment 节点不属于文档树。
    当请求把一个 DocumentFragment 节点插入文档树时,插入的不是 DocumentFragment 自身,而是它的所有子孙节点。这使得 DocumentFragment 成了有用的占位符,暂时存放那些一次插入文档的节点。它还有利于实现文档的剪切、复制和粘贴操作。

    P159

    获取下一个元素节点

    function getNextElement(node) {
        if (!node.nextSibling) return null;
        if (node.nextSibling.nodeType == 1) return node.nextSibling;
    
        return getNextElement(node.nextSibling);
    }
    

    P168

    添加 class 属性

    function addClass(element, value) {
        if (!element.className) {
            element.className = value;
        } else {
            newClassName = element.className;
            newClassName += ' ';
            newClassName += value;
            element.className = newClassName;
        }
    }
    

    P203

    Modernizr
    一个开源的 JavaScript 库。Modernizr 不会给你添加浏览器不支持的特性。

    P206

    实现当鼠标移到图片上时恢复彩色,鼠标离开图片时变为灰色的效果

    
    
    
    
    
        My Avatar
        
    
    
    

    P210

    在每个影片容器中,音频和视频轨道都使用不同的编解码器来编码。编解码器决定了浏览器在播放时应该如何解码音频和视频。编解码器的核心就是一个算法,用于压缩和存储视频,以减少原始文件的大小,同时可能会也可能不会损失品质。

    P212

    用 html5 在页面上制作一个视频播放器

    
    
    
        
        My Video
        
    
    
        

    P217

    检查浏览器是否支持某个输入类型的控件

    function inputSupportsType(type) {
        if (!document.createElement) return false;
        
        var input = document.createElement('input');
        input.setAttribute('type', type);
        if (input.type == 'text' && type != 'text') {
            return false;
        } else {
            return true;
        }
    }
    

    P218

    检查某元素是否有某属性

    function elementSupportsAttribute(elementName, attribute) {
        if (!document.createElement) return false;
        
        var elem = document.createElement(elementName);
        return ( attribute in elem );
    }
    

    如果浏览器不支持 placeholder 属性

    if (!elementSupportsAttribute('input', 'placeholder')) {
        var input = document.getElementById('first-name');
        
        input.onfocus = function() {
            var text = this.placeholder || this.getAttribute('placeholder');
            if (this.value == text) {
                this.value = '';
            }
        }
        
        input.onblur = function() {
            if (this.value == '') {
                this.value = this.placeholder || this.getAttribute('placeholder');;
            }
        }
        
        input.onblur();
    }
    

    P268

    内容分发网络
    对于库来说,如果有很多站点要使用同一个库,那么最好是把这个库托管到一个公共服务器上,以便所有站点共享和访问。这样,当用户从一个站点跳到另一个站点时,他们就不用再重复下载相同的文件了。

    内容分发网络(CDN, Content Delevery Network)可以解决分布共享库的问题。CDN 就是一个由服务器构成的网络,这个网络的用途就是分散存储一些公共的内容。CDN 中的每台服务器都包含库的一份副本,这些服务器分布在世界上不同的国家和地区,以便达到利用带宽和加快下载的目的。浏览器访问库的时候使用一个公共的 URL,而 CDN 的底层则通过地理位置最近、速度最快的服务器提供相应的文件。

    总结

    这本书到尾声了,这是我看的第一本真正意义上的 JavaScript 书籍。我最初学习 js 的时候看的那些教材只是简单的讲解了一些 js 的语法,没有什么深度。虽然这本书中提到知识点不多,但是却讲了一些使用 JavaScript 时的良好的规范,这些都是编程里最重要的东西。好像有句话叫“代码规范是编程思想的体现”来着,具体在哪看到的我忘了。

    平稳退化
    这本书提到的一个非常重要的规范,就是在浏览器不支持 JavaScript 的情况下保证页面能够正常运行而不至于崩掉。虽然现在的浏览器对 js 的支持都非常的棒,但是万一用户禁用了 JavaScript,那么页面会发生什么我也不知道,因为我从来没有禁用过 JavaScript。我之前写的 js 代码能够实现一些炫酷的效果,但是我从来都没有校验过浏览器是否支持那些方法,因为它们在我的浏览器上都能正常的运行-_-||。我以前还为那些炫酷的效果洋洋自得,现在看来这些都是些糟糕的代码。我个人觉得要做到平稳退化还是挺难的,脱离了 JavaScript 的页面岂不是变得很单调。

    渐进增强
    在浏览器不支持 JavaScript 的情况下要保证网页的基本功能不受影响,然后再在这个基础上使用 JavaScript 来增强交互性。如果你的网页一开始就是基于 JavaScript 构建的,那这不是一个好的网页结构。

    总之,养成良好的编码规范会使人终生受益。

你可能感兴趣的:(《JavaScript DOM编程艺术》笔记)