大家好,给大家分享一下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
- 组合(构造函数模式和原型模式):用构造函数定义实例属性,用原型定义方法和共享属性。
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