js复习
js知识点介绍
基础知识
1、原型、原型链
2、作用域、闭包
3、异步单线程
jsAPI
1、DOM操作
2、AJax
3、事件绑定
开发环境
1、版本管理
2、模块化
3、打包工具
运行环境
1、页面渲染
2、性能优化
一、原型和原型链
1、构造函数
<script>
function Foo(name,age){
this.name = name;
this.age = age;
this.class = 'class-1';
// return this; 默认有这一行
}
var f = new Foo('zhangsan',20);
var f1 =new Foo('lisi',22); //创建多个对象
</script>
2、构造函数--扩展
- var a = {}其实是var a = new Object()的语法糖
- var a = []其实是var a = new Array()的语法糖
- function Foo(){...}其实是var Foo = new Function(...)的语法糖
- 使用instanceof判断一个函数是否是一个变量的构造函数
- 判断一个变量是否为“数组”
- 变量 instanceof Array
3、原型规则和示例
5条原型规则
-
原型规则是学习原型链的基础
-
1、所有的引用类型(数组、对象、函数)都具有对象特性,即自由扩展特性(除了"null"以外)
var obj = {}; obj.a = 100; var arr = []; arr.a = 100; function fn(){}; fn.a = 100;
-
2、所有的引用类型(数组、对象、函数),都有一个__proto__属性,属性值是一个普通对象
console.log(obj.__proto__); console.log(arr.__proto__); console.log(fn.__proto__);
-
3、所有的函数,都有一个prototype属性,属性值也是一个普通对象。
console.log(fn.prototype)
-
4、所有的引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值
-
__proto__隐式类型原型
-
prototype显示类型原型
console.log(obj.__proto__ === Object.prototype)//true
-
5、当试图得到一个对象的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它的构造函数的prototype)中寻找。
//构造函数 function Foo(name,age){ this.name = name; } Foo.prototype.alertName = function(){ alert(this.name); } //创建实例 var f = new Foo('zhangsan'); f.printName = function(){ console.log(this.name); } //测试 f.printName();//zhangsan f.alertName(); //zhangsan
循环对象自身的属性 hasOwnProperty
var item;
for(item in f){
//高级浏览器已经在for in 屏蔽了来自原型的属性
if(f.hasOwnProperty(item)){
console.log(item);//name printName
}
}
4、原型链
5、instanceof
- f instanceof Foo的判断逻辑是
- f的__proto__一层一层往上,能否对应到Foo.prototype再试着判断f instanceof Object
问题
1、如何准确的判断一个变量是数组类型
var arr=[];
arr instanceof Array; //true
typeof arr; //Object,typeof是无法判断是否是数组的
2、写一个原型链继承的例子
//动物
function Animal() {
this.eat = function(){
console.log('animal eat');
}
}
//狗
function Dog(){
this.bark = function(){
console.log('dog bark');
}
}
Dog.prototype = new Animal();
var hashiqi = new Dog();//哈士奇
3、描述new 一个对象的过程
-
创建一个新对象
-
this指向这个新对象
-
执行代码即对this赋值
-
返回this
//构造函数 function Foo(name,age){ this.name = name; this.age = age; this.class = 'class-1'; } var f = new Foo('zhangsan',20)
4、写一个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');
div.html('<p>hello world').on('click',function(){
alert('clicked')
}).html('<p>javascript</p>')
二、作用域、闭包
1、执行上下文
-
1、范围:一段
<script>
或者一个函数 -
2、全局:变量定义、函数声明一段
<script>
-
3、函数:变量定义、函数声明、this.argument函数
-
ps:注意函数声明和函数表达式的区别
console.log(a);//undefined var a = 100;//函数声明 fn('zhangsan'); //'zhangshan' 20 function fn(name){//函数表达式 age = 20; console.log(name,age) var age; }
2、this
-
this要在执行时才能确定值,定义时无法确定
var a = { name: 'A', fn:function(){ console.log(this.name); } } a.fn();//this === a a.fn.call({name:'B'});//this === {name:'B'} var fn1 = a.fn; fn1(); //this === window;
-
(1)、作为构造函数执行
Function Foo(name){ this.name = name; } var f = new Foo('zhangsan')
-
(2)、作为对象属性执行
var obj = { name: 'A', printName:function(){ console.log(this.name) } } obj.printName();
-
(3)、作为普通函数执行
function fn(){ console.log(this) } fn();
-
(4)、callapplyind
function fn1(name,age){ alert(name); console.log(this); } fn1.call({x:100},'zhangsan',20) fn1.apply({x:100},['zhangsan',20]) var f2 = function (name,age){ alert(name); console.log(this); }.bind({y:200}); fn2('zhangsan',20)
3、作用域
-
1、没有块级作用域
-
2、只有函数和全局作用域
//无块级作用域 if(true){ var name = 'zhangsan'; } console.log(name);//zhangsan //函数和全局作用域 var a = 100; function fn(){ var a = 200; console.log('fn',a)//fn 200 } console.log('global',a)//global 100 fn();
4、作用域链
var a = 100;
function fn(){
var b = 200;
//当前作用域没有定义的变量,即自由变量
console.log(a)//100
console.log(b)//200
}
fn()
5、闭包
function F1(){
var a = 100;
//返回一个函数(函数作为返回值)
return function(){
console.log(a)//100自由变量父作用域寻找
}
}
//得到一个函数
var f1 = F1();
var a = 200;
f1();
6、闭包的使用场景
-
1、函数作为返回值
-
2、函数作为参数传递
function F1(){ var a = 100; return function(){ console.log(a) } } var f1 = F1(); function F2(fn){ var a = 200; fn(); } F2(f1);//100
问题
1、说一下变量提升的理解
-
变量升级 变量是在存储信息的容器
-
函数声明(注意和函数表达式的区别)
-
变量提升就是,在变量的作用域内,不管变量在何处声明,都会提升到作用域的顶部,但是变量初始化的顺序不变。
function test(){ a = 1; b = 2; var a b; console.log(a) console.log(b) }
2、说明this几种不同的场景
- 1、构造函数执行
- 2、作为对象属性执行
- 3、作为普通函数执行
- 4、call、apply、bind
3、如何理解作用链
- 自由变量
- 作用域链,即自由变量的查找
- 闭包的两个场景
实际开发中闭包的应用
//闭包实际应用中主要封装变量,收敛权限
function isFirstLoad(){
var _list = [];
return function(id){
if(_list.indexOf(id)>=0){
return false;
}else {
_list.push(id);
return true;
}
}
}
//使用
var firstLoad = isFirstLoad();
firstLoad(0);//true
firstLoad(10);//false
firstLoad(20);//true
//你在isFirstLoad函数外面,根本不可能修改掉_list的值
三、异步和单线程
- 什么是异步(对比异步)
- 前端使用用异步的场景
- 异步和单线程
1、什么是异步
console.log(100);
setTimeout(function(){
console.log(200)
},1000);
console.log(300);
//100 300 200顺序
//对比同步 同步会有阻塞
console.log(100);
alert(200);//几秒中之后单击确认
console.log(300);
//100 200 300
2、何时需要异步
- 在可能发生等待的情况
- 等待过程不能像alert一样阻塞程序运行,因此,所以的“等待的情况”都需要异步。
3、前端使用异步的场景
-
1、定时任务:setTimeout、setInverval
-
2、网络请求:ajax请求、动态加载
-
3、事件绑定
-
ajax请求代码示例
console.log('start') $.get('/data.json',function(data1){ console.log(data1); } console.log('end');//start end data1
-
加载示例
cosnole.log('start'); var img = document.createElement('img'); img.onload = function(){ console.log('loaded') } img.src = '/xxx.png'; console.log('end');//start end loaded
-
事件绑定示例
cosnole.log('start'); document.getElementById('btn1').addEventListener('click',function(){ alert('clicked'); }) console.log('end'); //start end clicked
4、异步和单线程
console.log(100);
setTimeout(function(){
console.log(200);
})
console.log(300);
//100 300 200
- 1.执行第一行,打印100。
- 2.执行setTimeout后传入setTimeout的函数会被暂存起来,不会立即执行(单线程的特点,不能同时干两件事)。
- 3.执行最后一行打印300。
- 4.待所有程序执行完,处于空闲状态时,会立马看有没有暂存起来的要执行。
- 5.发现暂存起来的setTimeout中的函数无需等待时间,就立即来过来执行。
问题
1、同步和异步区别是什么
- 1.同步会阻塞代码执行,而异步不会
- 2.alert是同步,setTimeout是异步
2、一个关于setTimeout的笔试题
console.log(1);
setTimeout(function(){
console.log(2);
},0)
console.log(3);
setTimeout(function(){
console.log(4)
},1000)
console.log(5);
//1 3 5 2 4
3、前端使用异步的场景有哪些
- 定时任务:setTimeout、setInverval
- 网络请求:ajax请求、动态加载
- 事件绑定
四、其他知识
知识点
- 日期、Math、数组API、对象API
1、日期
- Date.now() //获取当前时间的毫秒数
- var dt = new Date();
- dt.getTime(); //获取毫秒数
- dt.getFullYear(); //年
- dt.getMonth();//月(0-11)
- dt.getDate(); //日(0-31)
- dt.getHours();//小时(0-23)
- dt.getMinutes();//分钟(0-59)
- dt.getSeconds();//秒(0-59)
2、Math
- 获取随机数Math.random()
3、数组API
-
forEach 遍历所有元素
-
every 判断所有元素是否都符合条件
-
some 判断是否有至少一个元素符合条件
-
sort 排序
-
map 对元素重新组装,生成新数组
-
filter 过滤符合条件的元素
-
forEach
var arr = [1,2,3] arr.forEach(function(item,index){ //遍历数组的所有元素 console.log(index,item) })
-
every
var arr = [1,2,3]; var result = arr.every(function(item,index){ //用来判断所有的数组元素,都满足一个条件 if(item<4){ return ture } }) console.log(result)//true
-
some
var arr = [1,2,3]; var result = arr.some(function(item,index){ //用来判断所有的数组元素,只要有一个满足条件即可 if(item<2){ return true } }) console.log(result)//true
-
sort
var arr = [1,4,2,3,5]; var arr2 = arr.sort(function(a,b){ //从小到大排序 return a-b //从大到小的排序 return b-a }) console.log(arr2);
-
map
var arr = [1,2,3,4]; var arr2 = arr.map(function(item,index){ //将元素重新组装,并返回 return '<br>'+item+'</b>' }) console.log(arr2)
-
filter
var arr = [1,2,3]; var arr2 = arr.filter(function(item,index){ //通过某一个条件过滤数组 if(item>=2){ return true } }) console.log(arr2);//2 3
4、对象API for in
var obj = {x:100,y:200,z:300};
var key;
for(key in obj){
if(obj.hasOwnProperty(key)){
console.log(key,obj[key])
}
}
//x, 100;y ,200;z,300
解题
1、获取2019-02-16(当前时间)
function formatDate(dt) {
if(!dt){
dt = new Date();
}
var year = dt.getFullYear();
var month = dt.getMonth()+1;
var date = dt.getDate();
if(month < 10){
//强制类型转换
month = '0'+month;
}
if(date <10){
//强制类型转换
date = '0'+date;
}
//强制类型转换
return year + '-'+month + '-'+date;
}
var dt = new Date();
var formatDate = formatDate(dt);
console.log(formatDate);//2019-02-16
2、获取随机数,要求是长度一致的字符串格式
var random = Math.random();
random = random + '0000000000'//后面加上10个0
random = random .slice(0,10);
console.log(random)
3、写一个能遍历对象和数组的forEach函数
function forEach(obj,fn){
var key;
if(obj instanceof Array){
//准确判断是否是数组
obj.forEach(function(item,index){
fn(index,item);
})
}else {
//不是数组就是对象
for(key in obj){
if(obj.hasOwnProperty(key)){
fn(key,obj[key])
}
}
}
}
var arr = ['苹果','香蕉','梨'];
//注意,这里的参数的顺序换了,为了和对象的遍历格式一致
forEach(arr,function(index,item){
console.log(index,item)
// 0 "苹果"
// 1 "香蕉"
// 2 "梨"
})
var obj = {x:100,y:200};
forEach(obj,function(key,value){
console.log(key,value)
// x 100
// y 200
})