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');复制代码