1、基础知识
1.变量类型和计算
题目:
- js中使用typeof能得到的类型有哪些
- 何时使用===何时使用==
- js中有哪些内置函数
- js变量按照存储方式分为哪些类型,并描述其特点
- 如何理解json
知识点:
1.变量类型:值类型与引用类型
值类型:
var a=100;
var b=a;
a=200;
console.log(b);//100
引用类型:对象、数组、函数
var a={age:20};
var b=a;
b.age=21;
conlose.log(a.age)//21
typeof运算符:只能区分值类型的详细类型
typeof undefined //undefined
typeof 'abc' //string
typeof 123 //number
typeof true //boolean
typeof {} //object
typeof [] //object
typeof null //object
typeof console.log //function
2.变量计算
强制类型转换:
- 字符串拼接
var a=100+10; //110
var b=100+'10'; //'10010'
- ==运算符 (0、‘’、null、undefined都会转换成false)
null==undefined; //true
100=='100'; //true
0=''; //true
- if语句 (0、‘’、null、undefined都会转换成false)
var a=true
if(a){...}
var b=100
if(b){...}
var c=''
if(c){...}
- 逻辑运算
console.log(10&&0) ; //0
console.log(''||'abc') ; //'abc'
console.log(!window.abc); //true
var a=100;
console.log(!!a); //true
解答:
- undefined/string/number/boolean/object/function
- 参考jquery源码:
if(obj.a==null){
//相当于obj.a===null || obj.a===undefined 简写
}除此外,其他都用===
- 内置函数(数据封装类对象):Object Array Boolean Number String Function Date RegExp Error
- 值类型和引用类型
- json 只不过是一个 JS 对象而已,也是一种数据格式
- JSON.stringify({a:10,b:20}) 将对象转换为字符串
- JSON.parse('{"a":10,"b":20}') 将字符串变为对象
2.原型与原型链
题目:
- 如何准确判断一个变量是数组类型
- 写一个原型链继承的例子
- 描述new一个对象的过程
- 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',23);
- 构造函数-扩展
var a={} 其实是var a=new Object()的语法糖;
var a=[]其实是var a=new Array()的语法糖;
funtion() Foo(){...}其实是var Foo=Function(){...};
使用instanceof判断一个函数是否是一个变量的构造函数;
- 原型规则和示例
5条原型规则,原型规则是原型链的基础。
- 所有的引用类型(数组对象函数),都具有对象特性,即可自由扩展属性(除’null‘以外);
- 所有的引用类型,都有一个_proto_属性,属性值是一个普通的对象;
- 所有函数,都有一个prototype属性,属性值是一个普通的对象;
- 所有引用类型,_proto_属性值指向(完全等===)他的构造函数的prototype属性值;
- 当试图得到一个对象的某个属性时,若果这个对象本身没有这个属性,那么它的_proto_(即它的构造函数的prototype)中寻找。
示例:
1.原则i
var obj={};obj.a=100;
var arr=[];arr.a=100;
function fn(){};fn.a=100;
2.原则ii
console.log(obj._proto_);
console.log(arr._proto_);
console.log(fn._proto_);
3.原则ii
console.log(fn.prototype);
4.原则iv
console.log(obj._proto===Object.prototype)
5.原则v
function() Foo(name,age){
this.name=name;
}
Foo.prototype.alertName=function(){...}
var f=new Foo('zhangsan');
f.printName=function(){...}
f.printName();
f.alertName();
循环对象自身属性
var item;
for(item in f){
//高级浏览器已经在for in 中屏蔽了来自原型的属性,但这里建议大家加上这个判断,保 证程序的健壮性
if(f.hasOwnProperty(item)){
console.log(item)
}
}
- 原型链
function() Foo(name,age){
this.name=name;
}
Foo.prototype.alertName=function(){...}
var f=new Foo('zhangsan');
f.printName=function(){...}
f.printName();
f.alertName();
f.toString(); 要去f._proto_._proto_中查找
- 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(){}
}
function Dog(){
this.bark=function(){}
}
Dog.prototype=new Animal()
var hashiqi=new Dog()
3.创建一个对象,this指向这个新对象,执行代码即对this赋值,返回this,构造函数知识点。
4.慕课网搜索 zepto设计和源码分析
3.作用域和闭包
注:声明的变量和函数会被提升
//全局
console.log(a);
var a=100;
fn('zhangsan');
function fn(name){
//函数
console.log(this);
console.log(arguments);
age=20;
console.log(name,age);
var age
bar(100);
function bar(name){
console.log(name)
}
}
题目
- 说一下变量提升的理解
- 说明this几种不同的使用场景
- 创建10个<a>标签,点击的时候弹出来对应的序号
- 如何理解作用域
- 实际开发中闭包的应用
知识点
- 执行上下文(声明提升)
console.log(a);//undefined
var a=100;
fn('zhangsan'); //'zhangsan',20
function fn(name){
age=20;
console.log(name,age);
var age;
}
范围:一段<script>或者一个函数
全局:变量定义、函数声明、一段<script>
函数:变量定义、函数声明、this、arguments、函数
注意:函数声明和函数表达式的区别
- 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
作为构造函执行
function Foo(name){
this={};
this.name=name;
return this;
}
var f=new Foo('zhangsan');
作为对象属性执行
var obj={
name:'A',
printName:funtion(){
console.log(this.name);
}
}
obj.printName();
作为普通函数执行
function fn(){
console.log(this); //this===window
}
fn();
call apply bind
function fn(name){
alert(name);
console.log(this); //this===window
}
fn.call({x:100},'zhangsan');
- 作用域
没有块级作用域
只有函数和全局作用域
//无块级作用域
if(true){
var name='zhangsan'; //提升到if外面
}
console.log(name); //'zhangsan'
//函数和全局作用域
var a=100;
function fn(){
var a=200;
console.log('fn',a);
}
console.log('global',a);//全局 100
fn(); //函数 200
- 作用域链
var a=100
function fn(){
var b=200;
//当前作用域没有定义的变量,即“自由变量”
console.log(a);//去父级作用域取值,声明时的父作用域
console.log(b)
}
- 闭包
function F1(){
var a=100;
//返回一个函数(函数作为返回值)
return function(){
console.log(a);//去父级作用域取值,声明时的父作用域
}
}
var f1=F1();
var a=200;
f1();//100
使用场景:函数作为返回值,函数作为参数传递
解答
1.变量定义、函数声明提升
2.构造函数、对象属性、普通函数、call apply bind
3.
var i,a
for(i=0;i<10;i++){
(function(i){
var a=document.createElement('a');
a.innerHTML=i+'<br>';
a.addEventListener('click',function(e){
e.preventDefault();
alert(i)
})
document.body.appendChild(a);
})(i)
}
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();
firstLoad(10); //true
firstLoad(10); //false
firstLoad(20); //true
4.异步和单线程
题目
- 同步和异步的区别是什么?分别举例
- 一个关于setTimeout的笔试题
- 前端使用异步的场景有哪些
知识点
什么是异步(对比同步)有没有阻塞
异步:无阻塞
console.log(100)
setTimeout(function(){
console.log(200)
},1000)
console.log(300)
输出:100 300 200
同步:有阻塞
console.log(100)
alert(200) //几秒后点击确认
console.log(300)
前端使用异步的场景
在可能发生等待的情况,等待过程中不能像alert一样阻塞程序运行,因此,所有的等待的情况都需要异步。
- 定时任务setTimeout setInverval
- 网络请求:ajax请求,动态<img>加载
- 事件绑定
异步和单线程
单线程的特点:不能同时干两件事。
解答
同步会阻塞代码执行,而异步不会。
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 异步需要等待,所以2是5输出后才会执行
其他知识
题目
- 获取2017-06-10格式的日期
- 获取随机数,要求是长度一致的字符串格式
- 写一个能遍历对象和数组的通用forEach函数
知识点
日期
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)
Math
获取随机数Math.random() 0-1之间
数组API
forEach:遍历所有元素
var arr=[1,2,3]
arr.forEach(function(item,index){//值,索引
//遍历数组的所有元素
console.log(index,item)
})
every:判断所有元素是否都符合条件 返回true或false
var arr=[1,2,3]
var result=arr.every(function(item,index){
//用来判断所有的数组元素,都满足一个条件
if(item<4){
return true
}
})
console.log(result)
some:判断是否有至少一个元素符合条件 返回true或false
var arr=[1,2,3]
var result=arr.some(function(item,index){
//用来判断所有的数组元素,只要有一个满足条件即可
if(item<2){
return true
}
})
console.log(result)
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 '<b>' +item+'</b>'
})
console.log(arr2)
fileter:过滤符合条件的元素,返回符合条件的数组
var arr=[1,2,3]
var arr2=arr.filter(function(item,index){
//通过某一个条件过滤数组
if(item>=2){
return true
}
})
console.log(arr2)
对象API
for in
var obj={
x:100,
y:200,
z:300
}
var key
for(key in obj){//key就是obj的属性名,即x,y,z
//注意这里的hasOwnProperty,在讲原型链时候讲过
if(obj.hasOwnProperty(key)){
console.log(key,obj[key])
}
}
解答
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 date=formatDate(dt);
console.log(date);
var random=Math.random()
var random=random+'0000000000' //后面加10个零
var random=random.slice(0,10)
console.log(random)
function forEach(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]
forEach(arr,function(index,item){
console.log(index,item)
})
var obj={
x:100,
y:200
}
forEach(arr,function(key,value){
console.log(key,value)
})