javascript中的原型鏈
要弄清楚原型鏈就要先弄清楚 function 類型,在javascript中沒有類的概念,都是函數(shù),所以它是一門函數(shù)式的編程語言。類有一個很重要的特性,就是它可以根據(jù)它的構(gòu)造函數(shù)來創(chuàng)建以它為模板的對象。在javascript中,函數(shù)就有2個功能
第一、 作為一般函數(shù)調(diào)用
第二、 作為它原型對象的構(gòu)造函數(shù) 也就new()
我們來看一個例子
[javascript] view plain copyfunction a(){
this.name = ‘a(chǎn)’;
}
當創(chuàng)建一個函數(shù),它會發(fā)生什么呢?
第一、它會創(chuàng)建1個函數(shù)對象 也就是a 本身
第二、它會創(chuàng)建1個原型對象@a(用@來表示)
第三、函數(shù)對象會有一個prototype指針,它指向了對應(yīng)的原型對象,這里就指向了@a
第四、@a對象中有一個construtor指針,指向它的構(gòu)造函數(shù),這里就指向了a
這個prototype屬性究竟有什么用呢?
其實prototype 屬性表示當前函數(shù)能夠控制的范圍(或者說它指明了當前函數(shù)是誰的構(gòu)造函數(shù)),這里a就是@a原型對象的構(gòu)造函數(shù),所以我們會看見有這種寫法
?。踛avascript] view plain copyfunction a(){
this.name = ‘a(chǎn)’;
}
var a1 = new a();
這就和其他常見語言相似了,new 就是調(diào)用原型對象(通過prototype指針)里面構(gòu)造函數(shù)(constructor)創(chuàng)建一個新的對象實例。
那么修改了prototype指向?qū)ο罄锩娴膶傩?,也就影響了所有以它為模板?chuàng)建的實例,我們可以這樣來驗證
?。踛avascript] view plain copyfunction a(){
this.name = ‘a(chǎn)’;
}
var a1 = new a();
a.prototype.age = 1;
alert(a1.age);
結(jié)果:1
那為什么a1對象可以直接訪問到age屬性呢?a1對象里面我并沒有定義age屬性啊,
那是因為所有實例里面都會有一個引用_proto_(在firfox,chrome下可以直接訪問,ie不支持)指向了這個原型,這里就是指向了@a,
?。踛avascript] view plain copyfunction a(){
this.name = ‘a(chǎn)’;
}
var a1 = new a();
alert(a1._proto_ == a.prototype)
結(jié)果:true
在訪問屬性的時候,會先在a1對象內(nèi)部中尋找,如果沒有,就會順著_proto_指向的對象里面去尋找,這里會到@a中尋找,找到就返回值,沒有找到就返回undefined,用個成語來形容,就是順藤摸瓜嘛!
至此原型鏈的含義就出來了,由于原型對象也有一個_proto_指針,又指向了另一個原型,一個接一個,就形成了原型鏈。Object.prototype是最頂層的原型,所以如果修改了Object.prototype的屬性,那么就影響了所有的對象。
在來看一段代碼
?。踛avascript] view plain copyfunction a(){
this.name = ‘a(chǎn)’;
}
function b(){
this.age = 1;
}
b.prototype = new a();
alert(new b().name);
我們顯示的將b的原型指向了a的一個實例,然后,b的實例也可以訪問a的屬性了。這就是javascript的繼承了,那為什么b.prototype 指向的是a的一個實例,而不是直接指向a.prototype 呢?
?。踛avascript] view plain copyb.prototype = new a.prototype;
如果像上面這么寫,修改p.prototype中的屬性,那么a的原型也會改變了,相當于是子類修改了父類,并且子類和父類的屬性糅合在了一起,這顯然是不合適的。換句話說,b也成為了@a的構(gòu)造函數(shù),a,b成了平級的關(guān)系。
我們可以下一個定義:
函數(shù)a 繼承函數(shù)b 也就是讓函數(shù)a成為函數(shù)b原型的一個實例的構(gòu)造函數(shù),構(gòu)造函數(shù)里面聲明的屬性是函數(shù)a自己的,原型實例里面的屬性就是繼承b的
?。踛avascript] view plain copyvar $ = jQuery = function(selector,context){
//不可能在自己的構(gòu)造函數(shù)中又一次構(gòu)造自己,所以返回了另外一個構(gòu)造函數(shù)的實例
return new init(selector,context);
}
jQuery.fn = jQuery.prototype = {
size:function(){
return this.length;
}
}
function init (selector,context){
}
init.prototype = jQuery.fn;;
}
這是jquery的一段源碼,我們在使用jquery的時候,并沒有使用new關(guān)鍵字,那它是如何構(gòu)造對象的呢?
用上面的知識,可以解釋,jquery這里只是一個一般函數(shù)的調(diào)用,它返回了jquery原型的另外一個構(gòu)造函數(shù)創(chuàng)建的對象,也就是new init()
JavaScript中的原型
原型是JavaScript中一個比較難理解的概念,原型相關(guān)的屬性也比較多,對象有“[[prototype]]”屬性,函數(shù)對象有“prototype”屬性,原型對象有“constructor”屬性。
認識原型
開始原型的介紹之前,首先來認識一下什么是原型?
在JavaScript中,原型也是一個對象,通過原型可以實現(xiàn)對象的屬性繼承,JavaScript的對象中都包含了一個“ [[Prototype]]”內(nèi)部屬性,這個屬性所對應(yīng)的就是該對象的原型。
“[[Prototype]]”作為對象的內(nèi)部屬性,是不能被直接訪問的。所以為了方便查看一個對象的原型,F(xiàn)irefox和Chrome中提供了“__proto__”這個非標準(不是所有瀏覽器都支持)的訪問器(ECMA引入了標準對象原型訪問器“Object.getPrototype(object)”)。
實例分析
下面通過一個例子來看看原型相關(guān)概念:
function Person(name, age){
this.name = name;
this.age = age;
this.getInfo = function(){
console.log(this.name + “ is ” + this.age + “ years old”);
};
}
var will = new Person(“Will”, 28);
在上面的代碼中,通過了Person這個構(gòu)造函數(shù)創(chuàng)建了一個will對象。下面就通過will這個對象一步步展開了解原型。
Step 1: 查看對象will的原型
通過下面代碼,可以查看對象will的原型:
console.log(will.__proto__);
console.log(will.constructor);
結(jié)果分析:
“Person {}”對象就是對象will的原型,通過Chrome展開可以看到,“Person {}”作為一個原型對象,也有“__proto__”屬性(對應(yīng)原型的原型)。
在這段代碼中,還用到了“constructor”屬性。在JavaScript的原型對象中,還包含一個“constructor”屬性,這個屬性對應(yīng)創(chuàng)建所有指向該原型的實例的構(gòu)造函數(shù)。
通過“constructor”這個屬性,我們可以來判斷一個對象是不是數(shù)組類型
function isArray(myArray) {
return myArray.constructor.toString().indexOf(“Array”) 》 -1;
}
在這里,will對象本身并沒有“constructor”這個屬性,但是通過原型鏈查找,找到了will原型(will.__proto__)的“constructor”屬性,并得到了Person函數(shù)。
Step 2: 查看對象will的原型(will.__proto__)的原型
既然will的原型“Person {}”也是一個對象,那么我們就同樣可以來查看“will的原型(will.__proto__)的原型”。
運行下面的代碼:
console.log(will.__proto__ === Person.prototype);
console.log(Person.prototype.__proto__);
console.log(Person.prototype.constructor);
console.log(Person.prototype.constructor === Person);
結(jié)果分析:
首先看 “will.__proto__ === Person.prototype”,在JavaScript中,每個函數(shù)都有一個prototype屬性,當一個函數(shù)被用作構(gòu)造函數(shù)來創(chuàng)建實例時,該函數(shù)的prototype屬性值將被作為原型賦值給所有對象實例(也就是設(shè)置實例的__proto__屬性),也就是說,所有實例的原型引用的是函數(shù)的prototype屬性。了解了構(gòu)造函數(shù)的prototype屬性之后,一定就明白為什么第一句結(jié)果為true了。
prototype屬性是函數(shù)對象特有的,如果不是函數(shù)對象,將不會有這樣一個屬性。
當通過“Person.prototype.__proto__”語句獲取will對象原型的原型時候,將得到“Object {}”對象,后面將會看到所有對象的原型都將追溯到“Object {}”對象。
對于原型對象“Person.prototype”的“constructor”,根據(jù)前面的介紹,將對應(yīng)Person函數(shù)本身。
通過上面可以看到,“Person.prototype”對象和Person函數(shù)對象通過“constructor”和“prototype”屬性實現(xiàn)了相互引用(后面會有圖展示這個相互引用的關(guān)系)。
Step 3: 查看對象Object的原型
通過前一部分可以看到,will的原型的原型是“Object {}”對象。實際上在JavaScript中,所有對象的原型都將追溯到“Object {}”對象。
下面通過一段代碼看看“Object {}”對象:
console.log(Person.prototype.__proto__ === Object.prototype);
console.log(typeof Object);
console.log(Object);
console.log(Object.prototype);
console.log(Object.prototype.__proto__);
console.log(Object.prototype.constructor);
通過下面的代碼可以看到:
Object對象本身是一個函數(shù)對象。
既然是Object函數(shù),就肯定會有prototype屬性,所以可以看到“Object.prototype”的值就是“Object {}”這個原型對象。
反過來,當訪問“Object.prototype”對象的“constructor”這個屬性的時候,就得到了Obejct函數(shù)。
另外,當通過“Object.prototype.__proto__”獲取Object原型的原型的時候,將會得到“null”,也就是說“Object {}”原型對象就是原型鏈的終點了。
Step 4: 查看對象Function的原型
在上面的例子中,Person是一個構(gòu)造函數(shù),在JavaScript中函數(shù)也是對象,所以,我們也可以通過“__proto__”屬性來查找Person函數(shù)對象的原型。
console.log(Person.__proto__ === Function.prototype);
console.log(Person.constructor === Function)
console.log(typeof Function);
console.log(Function);
console.log(Function.prototype);
console.log(Function.prototype.__proto__);
console.log(Function.prototype.constructor);
結(jié)果分析 :
在JavaScript中有個Function對象(類似Object),這個對象本身是個函數(shù);所有的函數(shù)(包括Function,Object)的原型(__proto__)都是“Function.prototype”。
Function對象作為一個函數(shù),就會有prototype屬性,該屬性將對應(yīng)“function () {}”對象。
Function對象作為一個對象,就有“__proto__”屬性,該屬性對應(yīng)“Function.prototype”,也就是說,“Function.__proto__ === Function.prototype”
對于Function的原型對象“Function.prototype”,該原型對象的“__proto__”屬性將對應(yīng)“Object {}”
對比prototype和__proto__
對于“prototype”和“__proto__”這兩個屬性有的時候可能會弄混,“Person.prototype”和“Person.__proto__”是完全不同的。
在這里對“prototype”和“__proto__”進行簡單的介紹:
對于所有的對象,都有__proto__屬性,這個屬性對應(yīng)該對象的原型
對于函數(shù)對象,除了__proto__屬性之外,還有prototype屬性,當一個函數(shù)被用作構(gòu)造函數(shù)來創(chuàng)建實例時,該函數(shù)的prototype屬性值將被作為原型賦值給所有對象實例(也就是設(shè)置實例的__proto__屬性)
圖解實例
通過上面結(jié)合實例的分析,相信你一定了解了原型中的很多內(nèi)容。
但是現(xiàn)在肯定對上面例子中的關(guān)系感覺很凌亂,一會兒原型,一會兒原型的原型,還有Function,Object,constructor,prototype等等關(guān)系。
現(xiàn)在就對上面的例子中分析得到的結(jié)果/關(guān)系進行圖解,相信這張圖可以讓你豁然開朗。
對于上圖的總結(jié)如下:
所有的對象都有“__proto__”屬性,該屬性對應(yīng)該對象的原型
所有的函數(shù)對象都有“prototype”屬性,該屬性的值會被賦值給該函數(shù)創(chuàng)建的對象的“__proto__”屬性
所有的原型對象都有“constructor”屬性,該屬性對應(yīng)創(chuàng)建所有指向該原型的實例的構(gòu)造函數(shù)
函數(shù)對象和原型對象通過“prototype”和“constructor”屬性進行相互關(guān)聯(lián)
通過原型改進例子
在上面例子中,“getInfo”方法是構(gòu)造函數(shù)Person的一個成員,當通過Person構(gòu)造兩個實例的時候,每個實例都會包含一個“getInfo”方法。
var will = new Person(“Will”, 28);
var wilber = new Person(“Wilber”, 27);
前面了解到,原型就是為了方便實現(xiàn)屬性的繼承,所以可以將“getInfo”方法當作Person原型(Person.__proto__)的一個屬性,這樣所有的實例都可以通過原型繼承的方式來使用“getInfo”這個方法了。
所以對例子進行如下修改:
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function(){
console.log(this.name + “ is ” + this.age + “ years old”);
};
修改后的結(jié)果為:
原型鏈
因為每個對象和原型都有原型,對象的原型指向?qū)ο蟮母福傅脑陀种赶蚋傅母?,這種原型層層連接起來的就構(gòu)成了原型鏈。
在“理解JavaScript的作用域鏈”一文中,已經(jīng)介紹了標識符和屬性通過作用域鏈和原型鏈的查找。
這里就繼續(xù)看一下基于原型鏈的屬性查找。
屬性查找
當查找一個對象的屬性時,JavaScript 會向上遍歷原型鏈,直到找到給定名稱的屬性為止,到查找到達原型鏈的頂部(也就是 “Object.prototype”), 如果仍然沒有找到指定的屬性,就會返回 undefined。
看一個例子:
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.MaxNumber = 9999;
Person.__proto__.MinNumber = -9999;
var will = new Person(“Will”, 28);
console.log(will.MaxNumber);
// 9999
console.log(will.MinNumber);
// undefined
在這個例子中分別給“Person.prototype ”和“ Person.__proto__”這兩個原型對象添加了“MaxNumber ”和“MinNumber”屬性,這里就需要弄清“prototype”和“__proto__”的區(qū)別了。
“Person.prototype ”對應(yīng)的就是Person構(gòu)造出來所有實例的原型,也就是說“Person.prototype ”屬于這些實例原型鏈的一部分,所以當這些實例進行屬性查找時候,就會引用到“Person.prototype ”中的屬性。
屬性隱藏
當通過原型鏈查找一個屬性的時候,首先查找的是對象本身的屬性,如果找不到才會繼續(xù)按照原型鏈進行查找。
這樣一來,如果想要覆蓋原型鏈上的一些屬性,我們就可以直接在對象中引入這些屬性,達到屬性隱藏的效果。
看一個簡單的例子:
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function(){
console.log(this.name + “ is ” + this.age + “ years old”);
};
var will = new Person(“Will”, 28);
will.getInfo = function(){
console.log(“getInfo method from will instead of prototype”);
};
will.getInfo();
// getInfo method from will instead of prototype
對象創(chuàng)建方式影響原型鏈
會到本文開始的例子,will對象通過Person構(gòu)造函數(shù)創(chuàng)建,所以will的原型(will.__proto__)就是“Person.prototype”。
同樣,我們可以通過下面的方式創(chuàng)建一個對象:
var July = {
name: “July”,
age: 28,
getInfo: function(){
console.log(this.name + “ is ” + this.age + “ years old”);
},
}
console.log(July.getInfo());
當使用這種方式創(chuàng)建一個對象的時候,原型鏈就變成下圖了,July對象的原型是“Object.prototype”也就是說對象的構(gòu)建方式會影響原型鏈的形式。
hasOwnProperty
“hasOwnProperty”是“Object.prototype”的一個方法,該方法能判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性,因為“hasOwnProperty” 是 JavaScript 中唯一一個處理屬性但是不查找原型鏈的函數(shù)。
相信你還記得文章最開始的例子中,通過will我們可以訪問“constructor”這個屬性,并得到will的構(gòu)造函數(shù)Person。這里結(jié)合“hasOwnProperty”這個函數(shù)就可以看到,will對象并沒有“constructor”這個屬性。
從下面的輸出可以看到,“constructor”是will的原型(will.__proto__)的屬性,但是通過原型鏈的查找,will對象可以發(fā)現(xiàn)并使用“constructor”屬性。
“hasOwnProperty”還有一個重要的使用場景,就是用來遍歷對象的屬性。
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function(){
console.log(this.name + “ is ” + this.age + “ years old”);
};
var will = new Person(“Will”, 28);
for(var attr in will){
console.log(attr);
}
// name
// age
// getInfo
for(var attr in will){
if(will.hasOwnProperty(attr)){
console.log(attr);
}
}
// name
// age
javascript原型和原型鏈有什么特點
每個對象都會在其內(nèi)部初始化一個屬性,就是prototype(原型),當我們訪問一個對象的屬性時,
如果這個對象內(nèi)部不存在這個屬性,那么他就會去prototype里找這個屬性,這個prototype又會有自己的prototype,
于是就這樣一直找下去,也就是我們平時所說的原型鏈的概念。
關(guān)系:instance.constructor.prototype = instance.__proto__
特點:
JavaScript對象是通過引用來傳遞的,我們創(chuàng)建的每個新對象實體中并沒有一份屬于自己的原型副本。當我們修改原型時,與之相關(guān)的對象也會繼承這一改變。
當我們需要一個屬性的時,Javascript引擎會先看當前對象中是否有這個屬性, 如果沒有的話,
就會查找他的Prototype對象是否有這個屬性,如此遞推下去,一直檢索到 Object 內(nèi)建對象。
function Func(){}
Func.prototype.name = “Sean”;
Func.prototype.getInfo = function() {
return this.name;
}
var person = new Func();//現(xiàn)在可以參考var person = Object.create(oldObject);
console.log(person.getInfo());//它擁有了Func的屬性和方法
//“Sean”
console.log(Func.prototype);
// Func { name=“Sean”, getInfo=function()}
寫一個通用的事件偵聽器函數(shù)。
// event(事件)工具集,來源:github.com/markyun
markyun.Event = {
// 頁面加載完成后
readyEvent : function(fn) {
if (fn==null) {
fn=document;
}
var oldonload = window.onload;
if (typeof window.onload != ‘function’) {
window.onload = fn;
} else {
window.onload = function() {
oldonload();
fn();
};
}
},
// 視能力分別使用dom0||dom2||IE方式 來綁定事件
// 參數(shù): 操作的元素,事件名稱 ,事件處理程序
addEvent : function(element, type, handler) {
if (element.addEventListener) {
//事件類型、需要執(zhí)行的函數(shù)、是否捕捉
element.addEventListener(type, handler, false);
} else if (element.attachEvent) {
element.attachEvent(‘on’ + type, function() {
handler.call(element);
});
} else {
element[‘on’ + type] = handler;
}
},
// 移除事件
removeEvent : function(element, type, handler) {
if (element.removeEventListener) {
element.removeEventListener(type, handler, false);
} else if (element.datachEvent) {
element.detachEvent(‘on’ + type, handler);
} else {
element[‘on’ + type] = null;
}
},
// 阻止事件 (主要是事件冒泡,因為IE不支持事件捕獲)
stopPropagation : function(ev) {
if (ev.stopPropagation) {
ev.stopPropagation();
} else {
ev.cancelBubble = true;
}
},
// 取消事件的默認行為
preventDefault : function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
// 獲取事件目標
getTarget : function(event) {
return event.target || event.srcElement;
},
// 獲取event對象的引用,取到事件的所有信息,確保隨時能使用event;
getEvent : function(e) {
var ev = e || window.event;
if (!ev) {
var c = this.getEvent.caller;
while (c) {
ev = c.arguments[0];
if (ev && Event == ev.constructor) {
break;
}
c = c.caller;
}
}
return ev;
}
};
對Node的優(yōu)點和缺點提出了自己的看法?
*(優(yōu)點)因為Node是基于事件驅(qū)動和無阻塞的,所以非常適合處理并發(fā)請求,
因此構(gòu)建在Node上的代理服務(wù)器相比其他技術(shù)實現(xiàn)(如Ruby)的服務(wù)器表現(xiàn)要好得多。
此外,與Node代理服務(wù)器交互的客戶端代碼是由javascript語言編寫的,
因此客戶端和服務(wù)器端都用同一種語言編寫,這是非常美妙的事情。
*(缺點)Node是一個相對新的開源項目,所以不太穩(wěn)定,它總是一直在變,
而且缺少足夠多的第三方庫支持??雌饋恚拖袷荝uby/Rails當年的樣子。
Javascript如何實現(xiàn)繼承?
1、構(gòu)造繼承
2、原型繼承
3、實例繼承
4、拷貝繼承
原型prototype機制或apply和call方法去實現(xiàn)較簡單,建議使用構(gòu)造函數(shù)與原型混合方式。
function Parent(){
this.name = ‘wang’;
}
function Child(){
this.age = 28;
}
Child.prototype = new Parent();//繼承了Parent,通過原型
var demo = new Child();
alert(demo.age);
alert(demo.name);//得到被繼承的屬性
}
Javascript作用鏈域?
全局函數(shù)無法查看局部函數(shù)的內(nèi)部細節(jié),但局部函數(shù)可以查看其上層的函數(shù)細節(jié),直至全局細節(jié)。
當需要從局部函數(shù)查找某一屬性或方法時,如果當前作用域沒有找到,就會上溯到上層作用域查找,
直至全局函數(shù),這種組織形式就是作用域鏈。
javascript創(chuàng)建對象的幾種方式?
javascript創(chuàng)建對象簡單的說,無非就是使用內(nèi)置對象或各種自定義對象,當然還可以用JSON;但寫法有很多種,也能混合使用。
1、對象字面量的方式
person={firstname:“Mark”,lastname:“Yun”,age:25,eyecolor:“black”};
2、用function來模擬無參的構(gòu)造函數(shù)
function Person(){}
var person=new Person();//定義一個function,如果使用new“實例化”,該function可以看作是一個Class
person.name=“Mark”;
person.age=“25”;
person.work=function(){
alert(person.name+“ hello.。?!保?
}
person.work();
3、用function來模擬參構(gòu)造函數(shù)來實現(xiàn)(用this關(guān)鍵字定義構(gòu)造的上下文屬性)
function Pet(name,age,hobby){
this.name=name;//this作用域:當前對象
this.age=age;
this.hobby=hobby;
this.eat=function(){
alert(“我叫”+this.name+“,我喜歡”+this.hobby+“,是個程序員”);
}
}
var maidou =new Pet(“麥兜”,25,“coding”);//實例化、創(chuàng)建對象
maidou.eat();//調(diào)用eat方法
4、用工廠方式來創(chuàng)建(內(nèi)置對象)
var wcDog =new Object();
wcDog.name=“旺財”;
wcDog.age=3;
wcDog.work=function(){
alert(“我是”+wcDog.name+“,汪汪汪。。。。。?!保?
}
wcDog.work();
5、用原型方式來創(chuàng)建
function Dog(){
}
Dog.prototype.name=“旺財”;
Dog.prototype.eat=function(){
alert(this.name+“是個吃貨”);
}
var wangcai =new Dog();
wangcai.eat();
5、用混合方式來創(chuàng)建
function Car(name,price){
this.name=name;
this.price=price;
}
Car.prototype.sell=function(){
alert(“我是”+this.name+“,我現(xiàn)在賣”+this.price+“萬元”);
}
var camry =new Car(“凱美瑞”,27);
camry.sell();
CSS優(yōu)先級算法如何計算? * 優(yōu)先級就近原則,同權(quán)重情況下樣式定義最近者為準;
載入樣式以最后載入的定位為準;
優(yōu)先級為:
??!important 》 id 》 class 》 tag
important 比 內(nèi)聯(lián)優(yōu)先級高
iframe有那些缺點?
*iframe會阻塞主頁面的Onload事件;
*搜索引擎的檢索程序無法解讀這種頁面,不利于SEO;
*iframe和主頁面共享連接池,而瀏覽器對相同域的連接有限制,所以會影響頁面的并行加載。
使用iframe之前需要考慮這兩個缺點。如果需要使用iframe,最好是通過javascript
動態(tài)給iframe添加src屬性值,這樣可以繞開以上兩個問題。
HTML5的離線儲存怎么使用,工作原理能不能解釋一下?
在用戶沒有與因特網(wǎng)連接時,可以正常訪問站點或應(yīng)用,在用戶與因特網(wǎng)連接時,更新用戶機器上的緩存文件。
原理:HTML5的離線存儲是基于一個新建的.appcache文件的緩存機制(不是存儲技術(shù)),通過這個文件上的解析清單離線存儲資源,這些資源就會像cookie一樣被存儲了下來。之后當網(wǎng)絡(luò)在處于離線狀態(tài)下時,瀏覽器會通過被離線存儲的數(shù)據(jù)進行頁面展示。
如何使用:
1、頁面頭部像下面一樣加入一個manifest的屬性;
2、在cache.manifest文件的編寫離線存儲的資源;
CACHE MANIFEST
#v0.11
CACHE:
js/app.js
css/style.css
NETWORK:
resourse/logo.png
FALLBACK:
/ /offline.html
3、在離線狀態(tài)時,操作window.applicationCache進行需求實現(xiàn)。
Ajax是什么? 如何創(chuàng)建一個Ajax?
ajax的全稱:AsynchronousJavascript And XML。
異步傳輸+js+xml。
所謂異步,在這里簡單地解釋就是:向服務(wù)器發(fā)送請求的時候,我們不必等待結(jié)果,而是可以同時做其他的事情,等到有了結(jié)果它自己會根據(jù)設(shè)定進行后續(xù)操作,與此同時,頁面是不會發(fā)生整頁刷新的,提高了用戶體驗。
?。?)創(chuàng)建XMLHttpRequest對象,也就是創(chuàng)建一個異步調(diào)用對象
(2)創(chuàng)建一個新的HTTP請求,并指定該HTTP請求的方法、URL及驗證信息
?。?)設(shè)置響應(yīng)HTTP請求狀態(tài)變化的函數(shù)
?。?)發(fā)送HTTP請求
?。?)獲取異步調(diào)用返回的數(shù)據(jù)
(6)使用JavaScript和DOM實現(xiàn)局部刷新
同步和異步的區(qū)別?
同步:瀏覽器訪問服務(wù)器請求,用戶看得到頁面刷新,重新發(fā)請求,等請求完,頁面刷新,新內(nèi)容出現(xiàn),用戶看到新內(nèi)容,j進行下一步操作。
異步:瀏覽器訪問服務(wù)器請求,用戶正常操作,瀏覽器后端進行請求。等請求完,頁面不刷新,新內(nèi)容也會出現(xiàn),用戶看到新內(nèi)容。
AMD(Modules/Asynchronous-Definition)、CMD(Common ModuleDefinition)規(guī)范區(qū)別?
AsynchronousModule Definition,異步模塊定義,所有的模塊將被異步加載,模塊加載不影響后面語句運行。所有依賴某些模塊的語句均放置在回調(diào)函數(shù)中。
區(qū)別:
1. 對于依賴的模塊,AMD 是提前執(zhí)行,CMD 是延遲執(zhí)行。不過RequireJS 從 2.0 開始,也改成可以延遲執(zhí)行(根據(jù)寫法不同,處理方式不同)。CMD 推崇 as lazy as possible.
2. CMD 推崇依賴就近,AMD 推崇依賴前置。看代碼:
// CMD
define(function(require,exports, module) {
var a = require(‘。/a’)
a.doSomething()
// 此處略去 100 行
var b = require(‘。/b’) // 依賴可以就近書寫
b.doSomething()
// 。。。
})
// AMD 默認推薦
define([‘。/a’,‘。/b’], function(a, b) { // 依賴必須一開始就寫好
a.doSomething()
// 此處略去 100 行
b.doSomething()
// 。。。
})
DOM操作——怎樣添加、移除、移動、復(fù)制、創(chuàng)建和查找節(jié)點?
?。?)創(chuàng)建新節(jié)點
createDocumentFragment() //創(chuàng)建一個DOM片段
createElement() //創(chuàng)建一個具體的元素
createTextNode() //創(chuàng)建一個文本節(jié)點
?。?)添加、移除、替換、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子節(jié)點前插入一個新的子節(jié)點
?。?)查找
getElementsByTagName() //通過標簽名稱
getElementsByName() //通過元素的Name屬性的值(IE容錯能力較強,會得到一個數(shù)組,其中包括id等于name值的)
getElementById() //通過元素Id,唯一性
什么叫優(yōu)雅降級和漸進增強?
優(yōu)雅降級:Web站點在所有新式瀏覽器中都能正常工作,如果用戶使用的是老式瀏覽器,則代碼會針對舊版本的IE進行降級處理了,使之在舊式瀏覽器上以某種形式降級體驗卻不至于完全不能用。
如:border-shadow
漸進增強:從被所有瀏覽器支持的基本功能開始,逐步地添加那些只有新版本瀏覽器才支持的功能,向頁面增加不影響基礎(chǔ)瀏覽器的額外樣式和功能的。當瀏覽器支持時,它們會自動地呈現(xiàn)出來并發(fā)揮作用。
如:默認使用flash上傳,但如果瀏覽器支持HTML5 的文件上傳功能,則使用HTML5實現(xiàn)更好的體驗;
jsonp的原理是動態(tài)插入script標簽
跨子域可以采用iframe proxy的方式,支持GET和POST,支持異步POST。缺點是:范圍較窄,限定在“跨子域”,而且需要在目標服務(wù)器增加額外的文件。
JSONP的方式,支持雙向通信。只支持GET。缺點是:不支持POST,同時需要目標服務(wù)器在服務(wù)端支持。
iframe的window.name的方式,支持跨主域。缺點是:不支持POST,不過已經(jīng)很贊了:)
HTML5postMessage,支持雙向通信。缺點是:僅限于HTML5。結(jié)合window.name的方式,就很贊了
iframe + location.hash的方式跨主域,功能強大,兼容性好,支持跨域的js調(diào)用,支持雙向通信。缺點是:太復(fù)雜,會嵌套太多的iframe,同時數(shù)據(jù)直接寫在url中,數(shù)據(jù)大小受限而且數(shù)據(jù)暴露在外。
利用Flash跨域,優(yōu)點是支持強大,相對簡單。缺點是:依賴flash,需要在服務(wù)器更目錄放置crossdomain.xml文件。
為什么要有同源限制?
我們舉例說明:比如一個黑客程序,他利用Iframe把真正的銀行登錄頁面嵌到他的頁面上,當你使用真實的用戶名,密碼登錄時,他的頁面就可以通過Javascript讀取到你的表單中input中的內(nèi)容,這樣用戶名,密碼就輕松到手了。
作用域鏈的理解
每一段js代碼(全局代碼或函數(shù))都有一個與之關(guān)聯(lián)的作用域鏈(scope chain)。
當js需要查找變量x值的時候(這個過程稱為變量解析(variable resolution)),它會從鏈的第一個對象開始查找,如果這個對象有一個名為x的屬性,則會直接使用這個屬性的值,如果第一個對象中沒有名為x的屬性,js會繼續(xù)查找鏈上的下一個對象。如果第二個對象依然沒有名為x的屬性,則會繼續(xù)查找下一個,以此類推。
如果作用域鏈上沒有任何一個對象含有屬性x,那么就認為這段代碼的作用域鏈上不存在x,并最終拋出一個引用錯誤(ReferenceError)異常。
評論
查看更多