《前端JavaScript重点》学习笔记 1-5

JS三座大山:原型和原型连、作用域和闭包、异步和单线程
 
第一篇-----变量类型和计算  
题目:
1.JS中使用typeof能得到哪些类型
2.何时使用'===',何时使用'=='
3.JS有哪些内置函数
4.JS变量按照存储方式分为哪些类型,并描述其特点
5.如何理解JSON
知识点#####
  • 值类型vs引用类型
按照存储方式分为值类型和引用类型
引用类型 :数组、对象、null、函数。
其他是值类型。
 
//值类型
var a=100
var b=a
a=200
console.log(b) //100
 
//引用类型
var a={age:20}
var b=a
b.age=21
console.log(a.age) //21
引用类型:对象、数组、函数,由于引用类型占用内存空间较大,所以会出现公用内存空间的情况,变量a,b是指向某个内存空间的指针。而var b=a时,其实是b又指向了与a相同的内存空间,{age:20}仅存在一份。
 
  • typerof运算符详解
typeOf有五种基本类型。
typeof undefined   //undefined
typeof 'abc'   //string
typeof 123   //number
typeof true   //boolean
typeof {}// object
typeof [] // object
typeof null // object
typeof console.log //function
 
后四种都是引用类型,但typeof只能区分出函数,和值类型。
 
 
以下情况会发生强制类型转换:
  • 字符串拼接
'=='需要慎用,会试图进行类型转换使前后相等
  • if语句
          var a=true;
          if(a){        //true }
          var b = 100;
           if(a){ //true  }
          var a = '';
           if(a){   //false  }
  • 逻辑运算符
console.log(10  & 0) //0 转换为true&&0
console.log(''||'abc')  //abc 转换为false||'abc'
console.log(!window.abc)  //true !undefined为true
 
 
  • undefined 和 is not defined 不同,后者是报错,前者是未定义
 
解题#####
1.JS中使用typeof能得到哪些类型
undefined,string,number,boolean,object,function
2.何时使用'===',何时使用'=='
//仅有这种情况使用'==
'if(obj.a==null){
//此时条件相当于obj.a===null||obj.a===undefined,简写形式
//这是jQuery源码中推荐的写法
}
除此之外,其它情况均建议使用'==='
3.JS有哪些内置函数
Object,Array,Boolean,Number,String,Function,Date,RegExp,Error
4.JS变量按照存储方式分为哪些类型,并描述其特点
分为值类型和引用类型,值类型可以将数据分块存储在内存中,但是引用类型是多个变量共用一个内存块,引用类型的赋值是指定了一个指针,并不是真正的值的拷贝,它们之间是会相互干预的。
5.如何理解JSON
JSON是JS中的一个内置对象,也是一种数据格式
JSON.stringify({a:10,b:20})  //将对象转换为字符串
JSON.parse('{"a":10,"b":20}')  //把字符串转换为对象
 
 
 
 
 
 
 
第二篇-----原型与原型链
题目
1.如何准确判断一个变量是数组类型
2.写一个原型链继承的例子
3.描述new一个对象的过程
4.zepto框架中如何使用原型链
 
知识点
  • 构造函数
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) //创建多个对象
  • 构造函数-扩展
var a={} //其实是var a=new Object()的语法糖
var b=[] //其实是var b=new Array()的语法糖
function Foo(){...} //其实是var Foo=new Function(...)
使用instanceof判断一个函数是否是一个变量的构造函数
所有的引用类型(对象、数组、函数)都有构造函数,a的构造函数是Object(),b的构造函数是Array(),Foo的构造函数是Function()。所以假如想要判断一个变量是否为数组就可以使用
var a={}
a instanceof Array //false
 
  • 原型规则和实例(熟记)
    • 所有的引用类型都具有对象特性,即可自由扩展属性(null除外)
    • 所有引用类型都有一个__proto__(隐式原型属性),属性值是一个普通的对象
    • 所有函数都有一个prototype (显式原型属性),属性值也是一个普通的对象
    • 所有引用类型的__proto__属性值指向它的构造函数的prototype的属性值
    • 当试图得到一个引用类型的某个属性时,如果这个对象本身没有这个属性,那么会去它的__proto__(即它构造函数的prototype)中寻找
      var obj={};obj.a=100;
      var arr=[];arr.a=100;
      function fn(){}
      fn.a=100

      console.log(obj.__proto__)
      console.log(arr.__proto__)
      console.log(fn.__proto__)

      console.log(fn.prototype)

      console.log(obj.__proto__===Object.prototype) //true
 
//构造函数
function Foo(name,age){
    this.name=name
}
Foo.prototype.alertName=function(){  //由于prototype是一个普通对象,所以也可以扩展属性
    alert(this.name)
}
//创建实例
var f=new Foo('zhangsan')
f.printName=function(){
    console.log(this.name)
}
//测试
f.printName()  //zhangsan
f.alertName()  //f没有alertName属性,于是去f._proto_即Foo.prototype中查找
由对象调用原型中的方法,this指向对象
//循环对象自身的属性
var item   
//理论上有三个属性 name, printName,alertName 。但是自身的属性只有前两个,使用hasOwnProperty() 能过滤掉原型上的属性
for(item in f){
     //高级浏览器已在for in中屏蔽了来自原型的属性
    //但是这里建议还是加上这个判断以保证程序的健壮性
        if(f.hasOwnProperty(item)){
        console.log(item)
    }
}
  • 原型链
//在刚刚的代码中加入
f.toString()  //要去f.__proto__.__proto__中查找 找到了
所有的引用类型都有__proto__属性,且__proto__属性值指向它的构造函数的prototype的属性值,所以当f不存在toString时,便会在f.__proto__即Foo.prototype中查询,而Foo.prototype中也没有找到toString。由于Foo.prototype也是一个对象,所以它隐式原型__proto__的属性值便指向它的构造函数Object的prototype的属性值。
一个函数都会有显式原型属性,属性值是一个普通对象,(见原型规则3)。而普通对象的构造函数是Object
//试一试
console.log(Object.prototype)
console.log(Object.prototype.__proto__)  //为了避免死循环,所以此处输出null
 
原型链
  • instanceof
    用于判断引用类型属于哪个构造函数的方法
    f instanceof Foo  //true
           判断逻辑是f的__proto__一层层向上能否对应到Foo.prototype,再试着判断
           f instanceof Object  //true
 
解题#####
1.如何准确判断一个变量是数组类型
使用instanceof  (用于判断引用类型属于哪个构造函数的方法)
 
var arr=[]
arr instanceof Array  //true
typeof arr  //object typeof无法准确判断是否是数组
2.写一个原型链继承的例子
//简单示例,比较low,下面有更贴近实战的例子
//动物
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()
 
 
 
//更贴近实战的原型继承实例
//封装一个DOM查询
function Elem(id){
    this.elem=document.getElementById(id);
}
Elem.prototype.html = function(val){
    if(val){
        this.elem.innerHTML =val;
    }
    return this;            
}
 
Elem.prototype.on=function(type,fn){
    var elem=this.elem;
    elem.addEventListener(type,fn);
    return this;   //链式操作
}
 
var div1=new Elem('div1');
// console.log(div1.html());
// div1.html('<p>Hello</p>');
// div1.on('click',function(){
//      alert('clicked')
// });
div1.on('click',function(){
    alert('clicked');
}).html('<p>链式操作</p>');
//在之前的函数中增加了return this,由div1调用时便会返回当前对象,即div1,便可以实现链式操作
3.描述new一个对象的过程
function Foo(name,age){
    // this={}
    this.name=name;
    this.age=age;
    this.class='class-1';
    //return this;  //默认有这一行
}
var f=new Foo('zhangsan',20);
//var f1=new Foo('lisi',22); //创建多个对象
 
过程:
创建一个新对象   //{}
this指向这个新对象 this={}
执行代码,即对this赋值 this.xxx=xxx
返回this  return this
 
4.zepto框架如何使用原型链
 
 
 
 
第三篇-----作用域和闭包
 
题目
1.说一下对变量提升的理解
2.说明this几种不同的使用场景
3.创建10个<a>标签,点击时弹出对应序号
4.如何理解作用域
5.实际开发中闭包的应用
 
知识点#####
  • 执行上下文
 
范围:一段<script>或者一个函数  或者eval代码
全局:变量定义、函数声明  (提前拿出来)                    针对一段<script>
函数:变量定义、函数声明、this、arguments  (提前拿出来)                     针对一个函数
 eval不常用,也不推荐大家用。
 
在一段js代码拿过来真正一句一句运行之前,浏览器已经做了一些“准备工作”,在“准备工作”中完成了哪些工作:
1.变量、函数表达式——变量声明,默认赋值为undefined;
2.this——赋值;
3.函数声明——赋值;
这三种数据的准备情况我们称之为“执行上下文”或者“执行上下文环境”。
 
 
ps:注意函数声明和函数表达式的区别
//函数声明
function fn(){
    //.....
}
 
//函数表达式
var fn1=function(){
    //.....
}
 
//全局console.log(a); //undefined
var a=100
 
fn('zhangsan') //zhangsan 20
function fn(name){
    //函数
    console.log(this); //Window
    console.log(arguments); //"zhangsan"
    age=20
    console.log(name,age);
    var age   //age会提前
}
 
  • 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
 
  • - 作用域
js没有块级作用域
if(true){
    var name='zhangsan'
}
console.log(name); //zhangsan
只有函数和全局作用域
var a=100
function fn(){
    var a=200
    console.log('fn',a)
}
console.log('global',a)  //global 100
fn() //fn 200
  •  作用域链
自由变量
var a=100
function fn(){    
    var b=200    
    console.log(a) //当前作用域没定义的变量,即'自由变量'    
    console.log(b)
}
fn() //100 200
 
调用在当前作用域不存在的变量,便会向父级作用域查找。需要注意的是,父级作用域是函数定义时产生的,并非函数调用时。
var a=100
function F1(){
    var b=200
    function F2(){
        var c=300
        console.log(a) //a是自由变量,在F2中未找到便向父级作用域F1查找,仍未找到,继续向上查找,在Window中找到
        console.log(b) //b是自由变量
        console.log(c)
    }
    F2()
}
F1() //100 200 300
  • - 闭包
使用场景,函数作为返回值;函数作为参数传递
//闭包的使用场景:函数作为返回值
function F1(){
    var a=100
    //返回一个函数
    return function(){
        console.log(a)  //自由变量,父作用域查找,仍未找到,继续向上查找,在Window中找到
    }
}
//f1得到一个函数
var f1=F1()
var a=200
f1()  //100   
//闭包的使用场景:函数作为参数传递
function F1(){
    var a=100
    return function(){
        console.log(a)  //自由变量,父作用域查找
    }
}
var f1=F1()
function F2(fn){
    var a=200
    fn()
}
F2(f1)  //100
#####解题#####
**1.说一下对变量提升的理解**
在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。
在<script>或函数中,各个变量、函数的声明与定义会被提前
执行上下文。变量、函数表达式、this、函数声明,这几种数据的准备情况称之为“执行上下文”
 
**2.说明this几种不同的使用场景**
this的几种执行情况:
  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • call apply bind
//构造函数
function Foo(name){
    this.name=name
}
var f=new Foo('zhangsan')
 
 
//对象属性
var obj={
    name:'zhangsan',
    printName:function(){
        console.log(this.name)
    }
}
obj.printName()
 
 
//普通函数
function fn(){
    console.log(this);
}
fn()    //window
 
//call apply bind
function fn1(name,age){
    alert(name)
    console.log(this)    
}
fn1.call({x:100},'zhangsan',20)     //({x:100}
//apply
fn1.apply({x:100},['zhangsan',20])     //({x:100}
call, apply方法区别是,从第二个参数起, call方法参数将依次传递给借用的方法作参数, 而apply直接将这些参数放到一个数组中再传递
//bind
var fn2=function (name,age){  //bind在函数声明的形式后不可用,必须是函数表达式
    alert(name)
    console.log(this)
}.bind({y:200})
fn2('zhangsan',20)    //{y: 200}
**3.创建10个```<a>```标签,点击时弹出对应序号**
//错误的写法
    var i,a;
    for(i=0;i<10;i++){
//除了click函数内部,都为全局作用域,会被覆盖。因此最终 i 的值为10
//全局作用域
        a = document.createElement('a');
        a.innerHTML = i+'</br>' ;
        a.addEventListener('click',function(e){
            e.preventDefault();
            alert(i);  //i为自由变量,向上去父作用域查找时,值已经变成10. 因为click事件执行时,其它部分早已执行完毕。
        })        
        document.body.appendChild(a);
    }
    
//正确的写法
var i
for(i=0;i<10;i++){
//多包了一层,除了click函数,其它变量的作用于都变成了函数作用域,而不是全局作用域,因此不会被覆盖。相当于创建了10个函数
    (function (i){      
   //函数作用域
        var a=document.createElement('a')
        a.innerHTML=i
        a.addEventListener('click',function(e){
            e.preventDefault()
            alert(i)    //i为自由变量,向上去父作用域查找,就找到调用时的i值 (加粗处)
        })
        document.body.appendChild(a)
    }) (i)
}
 
工作实例:
不用闭包 结果永远是i的最大值+1,因此必须使用闭包
 
 
 
**4.如何理解作用域**
回答要点:
自由变量    //当前作用域没定义的变量,即'自由变量'    
作用域链,即自由变量的查找
闭包的两个场景
 
**5.实际开发中闭包的应用**
//闭包实际应用中主要用于封装变量,收敛权限
function isFirstLoad(){
    var _list=[]
    return function(id){
        if(_list.indexOf(id)>=0){
            return false
        }else {
            _list.push(id)
            return true
        }
    }
}
//使用
var firstLoad=isFirstLoad()9
firstLoad(10) //true
firstLoad(10) //false
firstLoad(20) //true
//在isFirstLoad函数外,无法修改_list的值
 
第四篇   异步和单线程
题目
1.同步和异步的区别是什么?分别举一个同步和异步的例子
2.一个关于setTimeout的笔试题
3.前端使用异步的场景有哪些
知识点#####
  • 什么是异步(对比同步)
//异步
console.log(100);
    setTimeout(function(){
    console.log(200);
},1000)
console.log(300);
// 100
// 300
// +1s后 200
 
//同步
console.log(100);
alert(200);
console.log(300);
//100
//对话框200
//关闭对话框后300
 
同步会出现阻塞,```alert(200)```不执行结束,后面的代码不会继续执行
- 前端使用异步的场景
在可能发生等待的情况。
等待的过程中不能像alert一样阻塞程序运行
因此所有的“等待的情况”都需要异步执行。
-1) 定时任务:setTimeout、setInterval
-2) 网络请求:ajax请求,动态```<img>```加载等
-3) 事件绑定
```
 
//ajax请求
console.log('start');
$.get('data/data1.json',function(data1){
    console.log(data1);
})
console.log('end');
//start
//end
//数据
```
```
//图片加载
console.log('start');
var img=document.createElement('img')
img.οnlοad=function(){
    console.log('loaded');
}
img.src='images/icon.jpg'
document.body.appendChild(img)
console.log('end');
//start
//end
//loaded
```
//事件绑定
```
console.log('start');
document.getElementById('btn1').addEventListener('click',function(){
    console.log('clicked')
})
console.log('end');
//start
//end
//点击打印clicked
```
 
 
 
- 异步和单线程
```
console.log(100);
setTimeout(function(){
    console.log(200);
})  //未设置等待时间
console.log(300);
//100
//300
//200
```
- 执行第一行,打印100
-  执行setTimeout后,传入setTimeout的函数会被暂存起来,不会立即执行(单线程的特点,不能同时执行两个任务)
- 执行最后一行,打印300
- 待所有任务执行完,处于空闲状态,才执行暂存的任务
- 暂存的setTimeout无等待时间,立即执行
 
#####解题#####
**1.同步和异步的区别是什么?分别举一个同步和异步的例子**
- 同步与异步最大的区别是阻塞代码,同步会阻塞代码,而异步不会
- 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
//+1s后 4
 
**3.前端使用异步的场景有哪些**
- 定时任务:setTimeout、setInterval
- 网络请求:ajax请求,动态```<img>```加载
- 事件绑定
 
它们共同的特点是需要等待,由于js是一个单线程语言,为了避免阻塞,所以要使用异步
 
第五篇   其它知识点(如date、Math、常用API)
 
1.获取2017-07-13格式的日期      //日期
2.获取随机数,要求是长度一致的字符串格式       //Math
3.写一个能遍历对象和数组的通用forEach函数       //数组API  对象API
知识点#####
  • 日期
Date.now()        //获取当前时间毫秒数
var dt=new Date()
dt.getTime()          //获取毫秒数
dt.getFullYear()         //年
dt.getMonth()        //月(0-11)
dt.getDate()       //日(0-31)
dt.getDay()       //星期(0 代表星期日, 1 代表星期一,2 代表星期二, 依次类推)
dt.getHours()     //小时(0-23)
dt.getMinutes()       //分钟(0-59)
dt.getSeconds()     //秒(0-59)
//获取的一切时间都是var dt=new Date()时的时间
  • Math
获取随机数Math.random()
 
  • 数组API
 1)forEach遍历所有元素
var arr=[1,2,3]
arr.forEach(function(item,index){
     // forEach() 方法对数组的每个元素执行一次提供的函数
    console.log(index,item);
})
//0 1
//1 2
//2 3
 
2) every判断所有元素是否符合条件
var arr=[1,2,3]
var result=arr.every(function(item,index){
    //every() 方法测试数组的所有元素是否都通过了指定函数的测试(所有!所有!)
    if(item<4){
         return true
    }
})
console.log(result);    //true
```
3) some 判断是否至少有一个元素符合条件
var arr=[1,2,3]
var result=arr.some(function(item,index){
     //some() 方法测试数组中的某些元素是否通过由提供的函数实现的测试,只需有一个满足条件即返回true
    if(item<2){
        return true
    }
})
console.log(result);  //true
```
4) sort 排序
var arr=[1,4,2,3,5]
var arr2=arr.sort(function(a,b){     //arr.sort()默认从小到大排序
//从小到大排序
return a-b
//从大到小排序
// return b-a
})
console.log('arr2:'+arr2);
//arr2:1,2,3,4,5
```
5) map 对元素重新组装,生成新数组
var arr=[1,2,3,4,5]
var arr2=arr.map(function(item,index){
    //将元素重新组装并返回
    return '<b>'+item+'</b>'
})
console.log(arr2);
// ["<b>1</b>", "<b>2</b>", "<b>3</b>", "<b>4</b>", "<b>5</b>"]
```
6) filter 过滤符合条件的元素
var arr=[1,2,3,4,5]
var arr2=arr.filter(function(item,index){
    // filter() 方法创建一个新数组, 其包含通过所提供函数实现的测试的所有元素
    if(item>=3){
        return true
    }
})
console.log(arr2);
// [3, 4, 5]
```
  • 对象API
var obj={
    x:100,
    y:200,
    z:300
}
var key
for(key in obj){
     //hasOwnProperty会返回一个布尔值,判断是否是原生的属性,以此来排除原型链上的属性
    if(obj.hasOwnProperty(key)){
        console.log(key,obj[key]);
    }
}
//x 100
//y 200
//z 300
```
解题#####
1.获取2017-07-13格式的日期
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
dt=new Date()
alert(formatDate(dt))
2.获取随机数,要求是长度一致的字符串格式
var random=Math.random()
var random=random+'0000000000'  //10个0
var random=random.slice(0,10)
//slice() 方法返回一个从0开始到1结束(不包括结束)选择的数组的一部分,浅拷贝到一个新数组对象。原始数组不会被修改console.log(random);
3.写一个能遍历对象和数组的通用forEach函数
function myForEach(obj,fn){
var key
if(obj  instanceof Array){
//判断是否为数组
    obj.forEach(function(item,index){
        fn(index,item)
    })
}else{
//不是数组就是对象
    for(key in obj){
        fn(key,obj[key])
     }
    }
}
 
var arr=[1,2,3]
//参数顺序换了,为了和对象的遍历格式一致
myForEach(arr,function(index,item){
    console.log(index,item);
})
 
var obj={x:100,y:200}
myForEach(obj,function(key,value){
    console.log(key,value);
})
/ /0 1
//1 2
//2 3
//x 100
//y 200
 
 
 
 
 
 
 
 
 
 
 

转载于:https://www.cnblogs.com/morongwendao/p/9585052.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值