Putting the script tag in the last can reduce the delay time, users won't wait a long time to open the webpage. Because the render direction is from top to bottom. javascript
Js have 7 data type in total, they are 6 primitives types and Object:
css
能返回6種,typeof只能區分primitives types和functionhtml
undefined typeof undefined
前端
string typeof 'abc'
java
number typeof 123
jquery
boolean typeof true
程序員
object typeof { } 或 typeof[ ] 或 typeof null
web
function typeof console.log
ajax
value type: Boolean, String, Number, null, undefined.express
var a=10;
var b=a;
a=20;
console.log(b) //10複製代碼
reference type: Array, Function. Object.
var a={age:20}
var b=a;
b.age=18;
console.log(a.age)//18;複製代碼
當value type作函數的參數時:函數內部的變量,也就是形參和實參只是簡單的賦值操做,兩個數據是獨立存儲於內存中的。在函數內部對形參進行修改,不會影響外面的變量。
var num=9; function changeNum(num){ num=10; console.log(num); } changeNum(num);//10 console.log(num);//9複製代碼
var val='xixi'; function a(val){ val=30; return val; } console.log(a(val)); //30 console.log(val); //xixi複製代碼
當reference type作函數參數時:仍是把實參存儲的地址賦值給了形參,在函數內部,形參一樣也指向該對象,因此在函數內部對該對象進行修改會影響到外面的變量。
var obj={name:"meryl"} function changeName(para){ para.name="jesscia"; } changeName(obj); console.log(obj.name); //jesscia; /* 注意:若是在函數內部從新建立對象,爲該形參賦值,那麼實參和形參這倆對象將再也不有關係,修改其中 一個,另一個不受影響,好比看下面的例子:*/ var obj2={name:"mohan"} function changeName(para){ para.name="lx"; para={name:'zoe'}; para.name='phoebe'; } changeName(obj2); console.log(obj2.name); //lx 複製代碼
Js共13類內置構造函數:Object Array Boolean String Number Date Function RegExp Error Global Math JSON
Undeclared is any variable that has not been declared yet. Console throws an error for this.
Undefined means a variable has been declared but has not yet been assigned a value.
Null is an assignment value, it can be assigned to a variable as a no value.
typeof(undefined); //undefined typeof(null); //object null == undefined //true null===undefined //false 複製代碼
i++ |
returns the value of a variable before it has been incremented |
++i |
returns the value of a variable after it has been incremented |
++i is more effective. because i++ can creative a buff variable to save the value before + operator. but ++i won't, like this example: i++ ===> m=1; i=i+1; ++i===>i=i+1;
Number.isNaN ('a') ; // false; |
單純的判斷是否是NaN |
isNaN('a'); // true |
判斷是否是數字 |
1. Use the bracket's syntax sugar to create an object
var obj={ name:'meryl', gender:'girl', sayHi:function(){console.log(`${this.name} is a ${this.gender}`)} } //缺點: 不能把json對象看成一個模板來進行new操做複製代碼
2. Use Object() constructor to create object
var obj=new Object(); obj.age=19; obj.show=function(){}; //缺點: 不能把json對象看成一個模板來進行new操做複製代碼
3. Use the function constructor to create an object
function Car(){ this.made="斯巴魯WRX"; this.show=function(){ console.log(this.made); } } var myCar=new Car();//經過構造函數,構造出一個對象出來 myCar.show();//斯巴魯WRX /* new內部的原理: 第一步:建立一個空對象 第二步:把this指向到那個空對象上 第三步:使空對象的_proto_指向構造函數的原型對象 第四步:當構造函數執行完後,若是無return的話,那麼就把當前的空對象返回 */複製代碼
4. Use function constructor+prototype to create an object
function Car(model){ this.made=model; } Car.prototype.show=function(){ console.log(this.made); } var car1=new Car('beetle'); var car2=new Car('BMW E46'); car1.show();//beetle car2.show();//BMW E46複製代碼
5. Use ES6 class syntax:
class myObj{ constructor(name){ this.name=name; } } var e = new myObj('meryl');複製代碼
6. Use Object.create( ), this method creates a new object extending the prototype object passed as parameter.
const person={ isHuman:false, printInfo:function(){ console.log(`My name is ${this.name}---Am I human? ${this.isHuman}`) } } const me = Object.create(person); me.name='meryl'; me.isHuman=true; // inherited propertied can be overwritten me.printInfo(); //My name is meryl---Am I human? true複製代碼
1. 顯式類型轉換有:Boolean Number String parseInt parseFloat
2. 隱式類型轉換有:+ - == !
Object.assign
JSON.parse(JSON.stringfy(obj))
undefined
或symbol
時,沒法拷貝1. for in
主要用於遍歷對象的可枚舉屬性,包括自有屬性,繼承自原型的屬性
var obj={name:"meryl", career:'FE'} Object.defineProperty(obj,"age",{value:"forever21",enumerable:false}); Object.prototype.protoPer1=function(){console.log("proto")}; Object.prototype.protoPer2=2; console.log("For in:"); for(var key in obj){ console.log(key); }複製代碼
輸出以下:
2. Object.keys
返回一個數組,元素均爲對象自有的可枚舉屬性
var obj={name:'meryl', career:'FE'}Object.defineProperty(obj,"age",{value:"forever21",enumerable:false}); Object.prototype.protoPer1=function(){console.log("proto")}; Object.prototype.protoPer2=2; console.log("Object.keys:"); console.log(Object.keys(obj));複製代碼
輸出以下:
3. Object.getOwnProperty
用於返回對象的自由屬性,包括可枚舉和不可枚舉的
var obj={name:'meryl', career:'FE'} Object.defineProperty(obj,"age",{value:"forever21",enumerable:false}); Object.prototype.protoPer1=function(){console.log("proto")}; Object.prototype.protoPer2=2; console.log("Object.getOwnPropertyNames:") console.log(Object.getOwnPropertyNames(obj));複製代碼
1. use Object.preventExtensions( ) to prevent new methods or properties being added to the object. (咱們不能像對象中添加新的屬性和方法了,可是還能修改原有的屬性):
var obj={name:'meryl'} Object.preventExtensions(obj);//阻止篡改對象 obj.age=21; console.log(obj.age);//undefined //修改原有的屬性: obj.name='sean'; console.log(obj.name);//sean複製代碼
2. use Object.seal( ) to seal an object. it not only makes an object as non-extensible but also gets objects' properties[[Configurable]] as false. it means we can't delete properties, but we still can modify the current properties.
var obj={name:'meryl'} //密封對象 Object.seal(obj); obj.age=21; console.log(obj.age); // undefined 不能添加新的屬性 delete obj.name; console.log(obj.name); //meryl 不能刪除對象的屬性複製代碼
3. use Object.freeze( ) to freeze an object. it makes an object as non-extensible and sealed also it set properties' [[Writable]] as false. it means we can't modify current properties.
var obj={name:'meryl'} //凍結對象 Object.freeze(obj); obj.age=21; console.log(obj.age); // undefined 不可擴展 delete obj.name; console.log(obj.name); //meryl 不可刪除 obj.name='sean'; console.log(obj.name);//meryl 不可修改複製代碼
三種方法的對比總結以下表所示:
1. using 'IIFE'(immediately-invoked function expression):
(function(){ var tmp='test'; })() console.log(tmp);//Uncaught ReferenceError: tmp is not defined複製代碼
2. use "let" keywords
this就是函數運行時所在的環境對象,(「this" means the environment object where the function is running.)
this做爲構造函數執行:就是經過這個構造函數能生成一個新對象,這時this就指向這個新對象
function Fn(name,age){ this.name=name; } var f=new Fn('meryl'); f.name// meryl複製代碼
this做爲對象屬性執行:
var obj={ a:1, b:function(){ console.log(this.a); } } obj.b();// this指向obj這個對象 var test=obj.b; test();//undefined 由於this指向了全局,全局中未定義變量a 複製代碼
this做爲普通函數執行:這是函數的最經常使用用法,屬於全局性調用,所以this就表明全局對象
var a = 1; function fn(){ console.log(this.a); } fn(); //1複製代碼
call, apply, bind: 他們都是函數的方法,能夠改變函數的調用對象
function fn(name,age){ console.log(name); console.log(this); } fn.call({x:100},'meryl',20); //meryl {x:100}複製代碼
Hoisting is a javascript mechanism where variables and function declarations are moved to the top of their scope before code execution. here is the example:
var a=3; fn(); function fn(){ var b=9; console.log(a); //undefined console.log(b); //9 var a=9; } console.log(a); //3複製代碼
A closure is an inner function that has access to the outer function's variables . The closure has three scope chains: it has access to its own scope, it has access to the outer function's variables, and it has access to global variables. For example:
function counter(){ var count=0; return function(){ count++; return count; } } var c1=counter(); c1();//1 c1();//2 var c2=counter(); c2();//1 c2();//2 c1();//3 this is not affected by c2;複製代碼
function isFirstLoad(id){ var list=[]; return function(id){ if(list.indexOf(id)>=0){ //說明不是第一次load了 return false; } else{ list.push(id); return true; } } }複製代碼
由於避免DOM渲染的衝突
用" 異步" 解決, 異步是個解決方案
單線程就是同時只作一件事,兩段JS不能同時執行, 緣由就是爲了不DOM渲染衝突,異步算是一種「無奈」的解決方案,雖然有挺多問題(缺點)。好比沒按照書寫方式執行,可讀性較差, callback中不容易模塊化。
異步是一個解決方案。具體的實現方式就是event-loop.
event-loop是JS實現異步的具體實現方式,原則是同步代碼直接按順序執行,異步代碼先放在異步隊列(queue)中,等全部的同步代碼/同步函數執行完畢後,輪詢執行異步隊列(queue)中的函數。
//例子1: setTimeout(function(){ console.log(1); }) console.log(2); /* 結果: 先輸出2,後1 主進程:console.log(2); 異步隊列:function(){console.log(1)} */ //例子2: setTimeout(function(){ console.log(1); },100) setTimeout(function(){ console.log(2); }) console.log(3); /* 結果: 先輸出3,後2,最後1 主進程:console.log(3); 異步隊列:function(){console.log(2)}馬上被放入queue中, 100ms以後function(){console.log(1)}被放入queue中 */ //例子3: $.ajax({ url:'http://google.com', success:function(result){console.log('a');} }); setTimeout(function(){console.log('b')},100); setTimeout(function(){console.log('c')});console.log('d'); /* 結果1: 先輸出d,後c, 再a, 最後b 結果2: 先輸出d,後c, 再b, 最後a 主進程:console.log('d'); 異步隊列:function(){console.log(c)}最早被放入queue中, .ajax或function(){console.log('b')}是不肯定哪個最被先放進去queue中的. */複製代碼
Here is a promise example:
結果以下:
//構造函數 function Person(name,age,job){ this.name=name; this.age=age; this.job=job; } Person.prototype.Intro=function(){ console.log(this.name+this.age) } Person.prototype.showJob=function(){ console.log(this.job) } //實例對象 var p1 = new Person('meryl',25,'web developer');複製代碼
new關鍵字和構造函數搭配使用,拿上面例子而言,其中背後的操做有分下面幾個步驟:
1. first create an empty object: p1{}function Person(name,age,job){ this.name=name; this.age=age; this.job=job; return this; }複製代碼4. set the instance object (p1) 's _proto_ links to the constructor function's prototype:
p1._proto_= Person.prototype (Person構造函數的原型對象)
注意:
下圖是構造函數,實例對象和原型對象的關係圖:
1. 全部的引用類型(array, function, object)都具備對象特性, 即 可自由擴展屬性 (除了null之外)
自由擴展屬性就好比:
var obj ={ }; obj.a=100; var arr=[ ]; arr.a=100; function fn(){ } fn.a=100; 複製代碼
2. 全部的引用類型(array, function, object)都有一個_proto_屬性(隱式原型),屬性值是一個普通的對象
console.log(obj._proro_); //_proto_是一個對象
console.log(arr._proro_); //_proto_是一個對象 console.log(fn._proro_); //_proto_是一個對象複製代碼
3. 全部的函數,都有一個prototype屬性(顯示原型),屬性值也是一個普通的函數
console.log(fn.prototype); //prototype也是一個對象複製代碼
4. 全部的引用類型(array, function, object)的_proto_屬性值指向它的構造函數的prototype屬性值 (構造函數的顯式原型===實例對象的隱式原型)
console.log( obj._proto_ === Object.prototype) //true 由於obj的構造函數就是Object console.log( arr._proto_ === Object.prototype) //true 由於arr的構造函數就是Object console.log( fn._proto_ === Object.prototype) //true 由於fn的構造函數就是Object複製代碼
5. 當試圖獲得一個對象的某個屬性時,若是這個對象自己沒有這個屬性,那麼會去它的_proto_(即它的構造函數的prototype)中尋找.
function Foo(name,age){ this.name=name; } Foo.prototype.alertName=function(){alert(this.name);} var f = new Foo('meryl'); f.printName=function(){console.log(this.name);} //printName是對象自身新添的一個屬性 f.printName()// this指向f,不用去f的構造函數的原型中找printName這個屬性 f.alertName()// this也指向f,其中alertName函數是f對象的原型中的函數複製代碼
what's the prototype:
The prototype is the property of constructor function, and It's an object. This prototype object can share methods and values among the instance objects. (每建立一個函數,函數上都會有一個屬性爲prototype. 它的值是一個對象,這個對象的做用就是當使用函數建立實例的時候,那麼那些實例都會共享原型上的屬性和方法)
what's the prototype chain?
The prototype chain is made of prototype objects. Each instance object has a property called '_proto_', this proto point to the object's prototype, but prototype also has his own prototype. In the final. The prototype will be null; This chain the structure is a prototype chain. (在JS中.每一個實例對象都有一個指向它原型對象(prototype)的內部連接叫_proto_, 這個原型對象又有本身的原型,直到某個對象的原型爲null爲止 ,這種一級級的鏈式結構就是原型鏈,當查找一個對象的屬性時,js會向上遍歷原型鏈,直到找到給定名稱的屬性爲止,到查找到達原型鏈的頂部,若仍然沒找到指定的屬性,就會返回undefined)
這是一個模仿jQuery中html(), on函數的例子:
//一個封裝DOM的例子: function Elem (id){ this.elem=document.getElementById(id); } Elem.prototype.html=function(val){ var elem=this.elem; if(val){ elem.innerHTML=val; return this;//鏈式操做 }else{ return elem.innerHTML; } } Elem.prototype.on=function(type,fn){ var elem=this.elem; elem.addEventListener(type,fn); return this; } var div1=new Elem('div1'); div1.html('<p>hello world</p>').on('click',function(){alert('clicked!')}).html('<p>JS</p>')複製代碼
This operator is used to check the type of an object at run time. The instanceof
operator returns a boolean value that indicates if an object is an instance of a particular class.(instanceof被用來判斷引用類型屬於哪一個構造函數). instanceof工做原理就是按着_proto_(隱式原型)往上找到prototype(顯示原型),後來進行隱顯式原型比對,同樣的話就返回true,不同則繼續往上找(由於prototype object中也有_proto_)
function forEach(obj,fn){ if(obj instanceof Array){ obj.forEach(function(item,index){ fn(index,item); }) }else{ for(var key in obj){ fn(key,obj[key]) } } } var arr=[1,2,4]; var obj={x:10,y:20}; forEach(arr,function(index,item){console.log(index,item)}); forEach(obj,function(key,value){console.log(key,value)});複製代碼
事件流模型包含三個階段:
Event propagation including event bubbling and event capturing, when an event occurs in an element inside another element and both elements have registered a handler for that event. The event propagation mode determines in which order the elements receive the event.
With bubbling, the event is first captured and handled by the innermost element and then propagated to outer elements.
With capturing, the event is first captured by the outermost element and propagated to the inner elements.
Because js allows DOM elements to be nested inside each other. If the handler of the child is clicked, the handler of the parent will also work as if it were clicked too. That sums up what event bubbling really is.
Event Delegation is the method. this method will let you create one event listener to trigger all child elements. Each child element will be targeted by a unique ID.
e.target |
The thing under the mouse (the thing that triggers the event) |
e.currentTarget |
is the element with the added event listener |
1. 使用Array.isArray( )
function is_array(arr){ if(Array.isArray(arr)){ return true; }else{ return false; } }複製代碼
2. 使用instanceof Array
function is_array(arr){ return arr instanceof Array; }複製代碼
3. 使用Object.prototype.toString.call( )=='[object Array]'
function is_array(arr){ return Object.prototype.toString.call(arr)=='[object Array]'; }複製代碼
這個問題考察了的知識點有:使用typeof判斷值類型,使用toString區分數組和對象;遞歸函數的使用..
function clone(obj){ //判斷是對象,就進行循環賦值 if(typeof obj ==='object' && typeof obj !=='null'){ //區分是數組仍是對象,建立空的數組或對象 var o = Object.prototype.toString.call(obj)==='[object Array]'?[]:{}; for(var k in obj){ //若是屬性對應的值爲對象,則遞歸賦值 if(typeof obj[k] ==='object' && typeof obj[k] !=='null'){ o[k]=clone(obj[k]) }else{ o[k]=obj[k]; } } } else{ //不是對象,直接把值返回 return obj; } retrun o; }複製代碼
what's Jquery chaining?
jquery chaining allows us to operate multiple actions on the same set of elements, all within a single line of code. like: $('div').html().css().removeClass()…
why the method could be a chain?
Because it returning a reference to this when the method finishes.
write example:
var testObj={ html:function(){console.log('method1');return this} css: function(){console.log('method2');return this} } testObj.html().css(); 複製代碼
DOM0 |
element.onclick=function(){ … } |
DOM2 |
element.addEventListener( 'click' , function(){…} , false ) 第三個參數默認是false,表示event bubbling |
DOM3 |
element.addEventListener( 'keyup' ,function(){…},false ) DOM3事件類型增多了,好比鼠標 鍵盤事件 |
The typical DOM event flow is conceptually divided into three phases: capture phase, target phase and bubbling phase.
what is reflow?
Reflow is the web browser process for re-calculating the positions of elements in the document, for the purpose of re-rendering the document.
what caused reflow?
How to reduce reflow?
let fn=(...args)=>{console.log(args)}; fn(1,2,'rest'); //[1,2,'rest'] function fn2(){ console.log(arguments); } fn2(1,2,'rest');複製代碼