javascript高级程序设计pdf,javascript 高级程序设计

大家好,给大家分享一下javascript高级程序设计 javascript权威指南,很多人还不知道这一点。下面详细解释一下。现在让我们来看看!

一、面向对象的程序设计

1. 属性类型
// 1.数据属性 object.defineproperty(属相所在的对象,属性名,(4种))
    let person = {};
    Object.defineProperty(person, "name", {
        configurable: true,  //表示能否通过delete删除属性从而重新定义属性,能否修改属性
        enumerable: true,  //表示能否通过for-in循环返回属性
        writable: true,  // 表示是否能修改属性的值
        value: "xujiang" // 属性的值
    })
    /* 在调用Object.defineProperty()方法创建一个新属性时,如不指定前三个属性字段,默认值都为false, 如果是修改已定义的属性时,则没有此限制 */

// 2.访问器属性get/set
    let person = {name: "xujaijgn", year: 11};
        Object.defineProperty(person, "_name", {
            get: function(){
                return this.name
            },
            // 定义Set时,则设置一个属性的值时会导致其他属性发生变化
            set: function(newValue){
                this.name = newValue;
                this.year = 12;
            }
        })

// 定义多个属性
Object.defineProperties(book, {
    _year: {
        writable: false,
        value: 2001
    },
    year: {
        get: function(){
            return _year
        },
        set: function(newValue){
            this._year = newValue;
        }
    }
})
2.创建对象
    原型理解:
     1.isPrototypeOf()-------确认对象之间有没有原型关系
     2.Object.getPrototypeOf()-------获取实例对象的原型
     3.我们不能通过实例重写原型中的值,只能访问,并且如果实例和原型有相同的属性名,则会覆盖原型中的属性。
     4.hasOwnProperty()-----检测一个属性是否在实例中
     5.原型与in操作符:“name" in person:对象能访问到给定属性时返回true
     6.Object.key(obj)---返回一个可以包含所有可枚举的属性
     7.Object.getOwnPropertyNames() ---返回所有的实例属性,包括不可枚举的
     8.实例中的指针只指向原型,而不是构造函数Python中的所有运算符号。 var person1=new Person() 那person1中的指针只指向Person.prototype 即 person1._proto_=Person.prototype   
  1. 组合(构造函数模式和原型模式):用构造函数定义实例属性,用原型定义方法和共享属性。
3.继承
1.原型链的问题
    1.包含引用类型值的原型属性会被所有实例共享,在通过原型实现继承时,原型实际上会变成另一个类型的实例,原先的实例属性变成了现在的原型属性。
    2.在创建子类型的实例时,无法向父类构造函数传递参数
    function Parent(name){
    this.name=name;
}
function  Child(){
}
Child.prototype=new Parent('zhangsan');
var p=new Chlid();//构造出来子类的实例没有办法向父类传参。
p.name;//可以继承父类的属性和方法

2.借用构造函数(在子类型构造函数的内部调用父类构造函数)
    //此时实例不会共享属性
    function Parent(name){
        this.colors = [1,3,4];
        this.name = name;
    }
    function Child(name){
        Parent.call(this, name);//但是实例化的子类能向父类传参。
        this.age = 12;
    }
    // 存在的问题: 1.函数无法复用 2.父类的原型对于子类是不可见的,子类不能继承原型上的属性和方法

3.组合继承(使用原型链继承原型属性和方法,使用借用构造继承实例属性) ---最常用的继承模式
    缺点:无论如何都会调用两次父类构造函数
    // 父类
    function Parent(name){
        this.name = "xujaing";
        this.age = 12;
    };
    Parent.prototype.say = function() { console.log(this.age) };
    // 子类继承父类
    function Child(name){
        Parent.call(this, name);//1
        this.age = 13;
    }
    Child.prototype = new Parent();//2
    Child.prototype.constructor = Child;
    Child.prototype.say = function() { alert(this.age) };

4.原型式继承
    实现1.
        function object(o){
            function F(){};
            F.prototype = o;
            return new F()
        }
    实现2.通过Object.create(prototype, properties) // 第一个参数为创建新对象原型的对象,第二个参数为对新对象定义额外属性的对象(和defineProperties方法的第二个参数格式相同)
  A=Object.create(person, {//A._proto_=Person
        name: {
            value: "xujiang"
        }
    })
5.寄生组合式继承(通过借用构造函数继承属性,通过原型链混成的方式继承方法)---最理想的继承范式
    function inheritPrototype(sub,sup){
        let prototype = Object.create(sup.prototype);//prototype._proto_=sup.prototype 
        prototype.constructor = sub;
        sub.prototype = prototype;
    }

    function Sup(){}
    Sup.prototype.say = function(){}
    function Sub(arg){
        // 关键
        Sup.call(this,arg);//var sub=new sup()
    }
    // 关键
    inheritPrototype(Sub, Sup);

二、函数表达式

闭包与变量

闭包:可以访问定义它们的外部函数的参数和变量(除了this和arguments)。
闭包的优点:封装私有变量,形成块级作用域。
缺点:内存泄漏占用内存。

function a(){
    let el = $("#el");
    let id = el.id;
    el.click(function(){
        alert(id)
    })
    // 清空dom,释放内存
    el = null;
}

三、BOM对象

Location对象:
// location即是window对象的属性也是document对象的属性
1. hash // "#contents" 返回url的hash,如果不包含返回空
2. host // "www.wrox.com:80" 返回服务器名称和和端口号
3. hostname // "www.wrox.com" 返回不带端口号的服务器名称
4. href // 返回当前加载页面的完整url
5. pathname // "/a/" 返回url中的目录或文件名
6. port // "8080" 返回url中指定的端口号
7. protocol // "http" 返回页面使用的协议
8. search // "?q=java" 返回url中查询字符串,以问号开头


navigator对象:
navigator.language // "zh-CN" 浏览器的主语言
navigator.appName  // "Netscape" 完整的浏览器名称
navigator.appVersion // 浏览器的版本
// 5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36
navigator.cookieEnabled // true 表示cookie是否启用
navigator.javaEnabled() // 表示浏览器是否启用java
navigator.onLine // true 表示浏览器是否连接到了因特网
navigator.platform // "Win32" 浏览器所在的系统平台
navigator.userAgent // 浏览器用户代理字符串
// "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36"
navigator.plugins // 检测浏览器中安装的插件的数组
history对象:
1. history.go(0 | [123] | -1 | str) // 如果是Str,则会跳转到历史记录中包含该字符串的第一个位置
2. history.back() //后退一页
3. history.forward() //前进一页
4. history.length // 保存着历史纪录的数量

四、DOM对象

1.将对象转化成数组 Array.prototype.slice.apply(arguments,[0]);
2.将字符串转化成数组:str.split(’ ')//split转化成字符串数组

1.appendChild() //用于向childNodes末尾添加一个节点,返回新增的节点,如果节点已存在,那么就是从原来的位置移动到新位置
2.insertBefore() //将节点插入指定位置,接收两个参数,要插入的节点和作为参照的节点,返回插入的节点
3.replaceChild() //替换指定节点,接收2个参数,要插入的节点和要替换的节点,返回被移除的节点
4.removeChild() //移除节点,返回被移除的节点
5.cloneNode([true]) //参数为true,执行深复制,复制节点及整个子节点,为false时复制节点本身。cloneNode不会复制节点的java属性,但IE在此存在一个bug,所以建议在复制之前最好先移除事件处理程序
document类型:
1. document的节点类型nodeType的值为9;
2. document.documentElement // 取得对<html>的引用
3. document.body // 取得对body的引用
4. document.title // 取得文章标题
5. document.title = "xxx" //设置文章标题
6. document.URL //取得完整的url
7. document.domain //取得域名
8. document.referrer //取得来源页面的url
element类型:
1.nodeType值为:1
2.nodeName的值为元素标签名
3.tagName // 元素标签名,返回大写值,比较时一般采用 element.tagName.toLowerCase()
4.取得元素属性 getAttribute() / setAttribute() / removeAttribute()
// 注:自定义属性通过点语法访问时会返回undefined
5.attributes // 获取元素的属性集合,访问方法: element.attributes[i].nodeName / element.attributes[i].nodeValue
6.创建元素 // document.createElement("div" | "<div class=\"box\">aaa</div>")
7.创建文本子节点 // document.createTextNode("Hello world")

五、元素大小

1.偏移量

offsetParent:获取元素的最近的具有定位属性(absolute或者relative)的父级元素。如果都没有则返回body
offsetHeight:元素在垂直方向上占用的空间大小。包括元素的高度、(可见的)水平滚动条的高度、上边框高度和下边框高度。(不包括外边框margin)
offsetWidth:元素在水平方向上占用的空间大小。包括元素的宽度、(可见的)垂直滚动条的宽度、左边框宽度号右边框宽度。
offsetLeft:元素的左外边框至父元素的左内边框之间的像素距离。
offsetTop:元素的上外边框至父元素的上内边框之间的像素距离。
偏移量

2.客户区的大小

clientWidth:元素内容区宽度加上左右内边距宽度。可以通过document.body。clientWidth来获取浏览器视口的大小。
clientHeight:元素内容区高度加上上下内边距高度
在这里插入图片描述

3.滑动大小

scrollHeight:元素内容的实际总高度
scrollWidth:元素内容实际总宽度
scrollLeft:被隐藏的内容区域左侧的像素数。通过设置这个属性可以改变元素的滚动的位置
scrollTop:被隐藏的内容区域上方的像素数。通过设置这个属性可以改变元素的滚动位置
在这里插入图片描述

六、事件

1.事件对象event
1. 属性或方法
    type // 被触发的事件类型
    target // 事件的目标 触发事件的元素li
    currentTarget // 事件处理程序当前正在处理事件的那个元素 邦定事件的元素ul
    注: 在事件处理程序内部,对象this始终等于currentTarget的值,而target只包含事件的实际目标
    *** 一个函数处理多个事件可以使用switch(event.type)的方式
    event.preventDefault() // 阻止事件的默认行为
    event.stopPropagation() // 阻止事件冒泡
2.事件类型
1.鼠标和滚轮事件
    1.客户区坐标位置clientX/clientY  //表示事件发生时鼠标指针在视口中的水平和垂直位置
    2.页面坐标位置 pageX/pageY  //表示事件在页面中发生的位置
    3.屏幕坐标位置 //获取事件发生时在屏幕中的位置

2.修改键(如果用户在触发事件时按下了shift/ctrl/alt/Meta,则返回true)
    event.shiftkey | event.altKey | event.metaKey | event.ctrlKey

3.鼠标按钮(event.button)
// 对于mousedown和mouseup,其event中存在一个button属性,值为0表示主鼠标按钮,1表示中间鼠标按钮,2表示次鼠标按钮

4.鼠标滚轮事件(mousewheel)
    1.兼容方案:
        let getWheelDelta = function(event){
            let wheelDelta = event.wheelDelta ? event.wheelDelta : (-event.detail * 40);
            return wheelDelta
        }
    *** 注:document在普通浏览器中通过mousewheel监听鼠标滚轮事件,在火狐中使用DOMMouseScroll监听

5.键盘与文本事件
6.变动事件
    1.DOMSubtreeModified | DOMNodeInserted | DOMNodeRemoved
    *例子
        el.addEvent("DOMSubtreeModified", fn1)

7.HTML5事件
    1.contextmenu事件(自定义上下文菜单)
    2.DOMContentLoaded事件(在形成完整dom树之后就触发,不理会图像,js文件,css文件等资源是否下载完成)
    3.hashchange事件(在URL的参数列表发生变化【即#号后面的所有字符串】时触发)
    注:必须要把hashchange添加给window对象,event对象包含两个属性oldURL和newURL,分别保存着参数列表变化前后的完整URL  vue的路由就是这个机制 通过haschange来监听url的变化,实现url改变但是不刷新页面的多页面的效果
    // 例子
    window.addEvent("hashchange", function(event){
        // oldURL和newURL存在兼容问题,最好用location.hash代替
        console.log(event.oldURL, event.newURL);
    })
3.性能问题

当你卸载页面时,事件处理占用的内存没有释放。所以在卸载之前通过unonload事件移除所有事件的处理程序。并且不会保存在缓存中。

七、跨域文档传递iframe

// 源页面
window.onload = function(){
    // 获取源页面iframe的内容window对象
    var iframeWindow = document.querySelector("#iframe").contentWindow;
    // 向iframe发送消息,并指定源的地址,两个参数必填
    iframeWindow.postMessage("xujiang", "http://127.0.0.1:5500");

    var mesWrap = document.querySelector(".mes-wrap");
    // 接收iframe传来的消息
    window.addEventListener("message",function(e){
    // alert(e.data);
        mesWrap.innerHTML = e.data;
        iframeWindow.postMessage("你叫什么?", "http://127.0.0.1:5500");
    },false);
}

// iframe页面,监听其他域传来的消息
window.addEventListener("message",function(e){
    // 向发送消息的域反馈消息,event对象的属性如下:
    // data 传入的字符串数据
    // origin 发送消息的文档所在的域
    // source 发送消息的文档的window的代理
    e.source.postMessage("hello", "http://127.0.0.1:5500");
},false);

八、ajax和cors

// ajax
var xhr = new XMLHttpRequest(); // 创建xhr对象

// 第一个方法:open(get | post等, "exam.php", false) 参数为请求类型,请求url,是否异步的boolean
xhr.open("get","exam.php", false); // 调用该方法并不是真正的请求,而是请求一个请求以备发送

// 发送真正的请求,接收一个参数,即作为请求主体要发送的数据,不发送数据时必须传递null,因为对于某些浏览器来说该参数是必须的
xhr.send(null)

// 检验响应的状态--->针对同步
if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
    var data = xhr.responseText;
}else{
    console.log(xhr.status);
}

// 异步方案
xhr.onreadystatechange = function(){
    // xhr.readyStatus表示请求/响应过程的当前活动阶段
    // 0 未初始化,还没调用open()
    // 1 启动,已调用open()方法但未调用send()
    // 2 发送, 已调用send()方法,但未收到响应
    // 3 接收,已接收到部分响应数据
    // 4 完成,已接受到全部响应数据
    if(xhr.readyStatus == 4){
        if(xhr.status >= 200 && xhr.status < 300 || xhr.status == 304){
            var data = xhr.responseText;
        }else{
            console.log(xhr.status);
        }
    }
}
xhr.open("get","exam.php", false);
xhr.send(null);

// 在接收到响应之前还可以取消异步请求
xhr.abort() // 在停止请求之后还应该进行解引用操作,防止内存堆积

// 设置http请求头,必须放在open和send中间
xhr.open("get","exam.php", false);

xhr.setRequestHeader("accept", "application/json; charset=utf-8")

xhr.send(null);

// 获取响应头信息
xhr.getResponseheader("accept");
xhr.getAllResponseHeaders();

// get请求:向现有url中添加查询字符串
function addUrlParam(url, name, value){
    url += (url.indexOf("?") == -1 ? "?" : "&");
    url += encodeURIComponent(name) + "=" + encodeURIComponent(value);
}

// post请求:模拟表单提交
xhr.open("get","exam.php", false);
// 设置提交时的内容类型
xhr.setRequestHeader("content-Type", "application/x-www-form-urlencoded")
// 假设表单form对象已获取
xhr.send(serialize(form));

// XHR2级 -- formData --序列化表单以及创建和表单格式相同的数据(用于通过xhr传输)
var data = new FormData();
data.append(key,value);
// 也就可以用表单元素的数据预先填入数据
var data = new FormData(document.forms[0]);
//使用FormData的好处在于不必明确地在xhr上设置请求头部
xhr.send(new FormData(form));

// 进度事件
loadStart/progress/error/abort/load

// 跨域资源共享CORS
核心思想: 使用自定义的http头部让浏览器和服务器进行沟通,从而决定请求是成功还是失败
原理:
1.请求头指定源:Origin: http://www.baidu.com
2.如果服务器认为这个请求可以接受,就在Access-Control-Allow-Origin头部回发相同的源信息
Access-Control-Allow-Origin:http://www.baidu.com
(如果是公共资源,可以回发“*”)
3.如果没有这个头部,或者有这个头部但是源信息不匹配,浏览器就会驳回请求

// 主流浏览器对cros的实现方式: 在url中使用绝对路径,但有限制:不能设置自定义头部,不能发送和接收cookie,获取不到getAllResponseHeaders()的返回值

// 带凭据的请求
withCredentials属性设置为true
// 服务器接收到带凭据的请求后,会用下面的头部来请求,如果响应不包含这个头部,浏览器将不会把响应数据交给js
Access-Control-Allow-Credentials: true

// 跨浏览器的cros
function createCORSRequest(method,url){
    var xhr = new XMLHttpRequest();
    if("withCredentials" in xhr){
        xhr.open(method,url,true);
    }else if(typeof XDomainRequest != "undefined"){
        xhr = new XDomainRequest();
        xhr.open(method,url);
    }else{
        xhr = null;
    }
    return xhr
}
var req = createCORSRequest("get","http://www.baidu.com/page/");
if(req){
    req.onload = function(){
        // 对响应数据进行处理
    };
    req.send();
}
// 以上提供的公共方法有
// abort() 用于停止正在进行的请求
// onerror 用于替代onreadystatechange检验错误
// onload 用于替代onreadystatechange检验成功
// responseText 用于取得响应内容
// send() 用于发送请求

// 其他跨域技术
1.图像ping---常用于跟踪用户点击页面和动态广告曝光数,只能get请求
    var img = new Image();
    img.onload = img.onerror = function(){
        // 操作
    }
    img.src = "http://baidu.com?name=xujaing";

2.JSONP---可以直接访问响应文本,可以在浏览器和服务器之间进行双向通信,但有安全隐患
    function handleResponse(data){
        console.log(data);
    }
    var  = document.createElement("");
    .src = "http://a.net/json/?callback=handleResponse";
    document.body.insertBefore(, document.body.firstChild);

3.Comet (服务器推送SSE)
    常用的技术有长轮询和流
4.Web Sockets

九、高级技巧

1.高级函数
1.Object.prototype.toString.call(value) == "[object Array]";//检测数据类型
2.//原生实现bind 柯理化思想 
//1.this 指向 apply /call2.参数形式 可以通过call(参数多)和apply实现(apply更方便)3.返回一个待执行的函数 闭包
function testBind(that){
  var _this=this;
  var args=Array.prototype.slice.apply(arguments,[1]);//通过slice将arguments转换成数组,取得bind的除第一个参数以外的参数
  return function(){
  return _this.apply(that,args.concat(Array.prototype.slice.apply(arguments,[0])))
}

}
2.高级定时器
//防抖
function decouce(fn,wait){
var timer=null;
return function(){
clearTimeout(timer);
var timer=setTimeout(()=>{
     fn();

},wait);
}
}
//节流
function throttle(fn,time,wait){
var pre=null;
var timer=null;
var now=new Date();
if(pre==undifined) pre=now;
if(now-pre>time){
 clearTimeout(timer);
    fn();
    pre=now;
}else{//小于time那么在wait内再执行一次
clearTimeout(timer)
 timer=setTimerout(()=>{
 fn();
},wait)
}
}

十、新的API

1.requestAnimationFrame():计时器不需要设置时间间隔,比其他两种精准
(function(){
    function draw(timestamp){
        // 计算两次重绘的时间间隔
        var drawStart = (timestamp || Date.now()),
        diff = drawStart - startTime;

        // 使用diff确定下一步的绘制时间

        // 把startTime重写为这一次的绘制时间
        startTime = drawStart;

        // 重绘UI
        requestAnimationFrame(draw);
    }

    var requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame,
    startTime = window.mozAnimationStartTime || Date.now();
    requestAnimationFrame(draw);
})();

https://www.cnblogs.com/AI-fisher/p/11178130.html
https://zhuanlan.zhihu.com/p/84326290