1. typeof判断类型
javascript 的原始类型包括:
两个未定义类型:undefined,null;
常用三种:number boolean string
JavaScript的引用类型 object
其中object包括了:function array date
2
问题三:
3.1 如何判断一个变量是数组类型
3.2 写一个原型链继承的例子
3.3 描述 new 一个对象的过程
3.4 zepto(或其他框架)源码中如何使用原型链
背景知识介绍:
// 构造函数 首字母大写 类似于模板function Foo(name,age){ this.name = name; this.age = age; this.class = 'class-1'; // return this //默认有这一行} // 每次new一个类的时候,this先变成空对象,然后在赋值this的name等值,最后在return 出来给new出来的f,则f.name=zhangsanvar f = new Foo('zhangsan',20); //创建多个对象var f1 = new Foo('lisi',22);
所有的引用类型(数组/对象/函数),都具有对象特性,即可以自由扩展属性(除了null以外)如 var obj = {}; obj.a=1000;
所有的引用类型(数组、对象、函数),都有一个 _proto_ (隐式原型)属性,属性值是一个普通的对象。
所有的引用类型(数组、对象、函数),_propto_属性值指向它的构造函数的 “protptype”属性值
其中this指向对象本身。
上面f有三个属性: name,alertName,printName;
为了拿到它自身的属性name,printName:
例如在实例f中调用,本来没有定义过的 f.toString()方法,就按照下图所示,一级一级原型链的往上找:(注意Object的原型是null,避免导致死循环)
instanceOf 用于判断 引用类型 属于哪个 构造函数的方法;
判断f是否输入对象,首先根据原型链找到父级 Foo,无法判断,则再找上一级,一直找到Object
或者把Animal类的方法提取出来:
function Animal(){}Animal.prototype.eat = function(){ console.log('eat');}function Dog(){ this.bark = function(){ console.log('dog bark'); }}Dog.prototype = new Animal();var hashiqi = new Dog();hashiqi.bark();hashiqi.eat();
写一个原型继承的例子:
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('hello
');div1.on('click',function(){ alert('clicked');})/*可以链式操作:div1.html('hello
').on('click',function(){ alert('clicked');})*/
问题四:
4.1 说一下对变量提升的理解
4.2 说明this几种不同的使用场景
4.3 创建10个<a>标签,点击的时候弹出来对应的序号
4.4 如何理解作用域
4.5 实际开发过程中闭包的应用
=======================
4.1.1 执行上下文
范围: 一段<script>或者一个函数
全局:变量定义/函数声明
函数:变量定义,函数声明/this/arguments
console.log(a); //undefinedvar a = 100;fn('zhangsan'); //'zhangsan' 20function fn(name){ age = 20; console.log(name,age); var age;}
函数和变量的声明先提取到前面,不同的是变量的提升会用undefined占位,如 var a = undefined 占位,尚未执行到var a = 100 赋值;
而函数声明会把整个函数先提取到前面:在执行到函数 fn(‘zhangsan’)的时候 在看函数内部: 首先提升age变量;
4.2 this要在执行时才能确认值,定义时无法确认:
var a = { name:"A", fn:function (){ console.log(this.name); }}a.fn(); //this === Aa.fn.call({name:"B"}) //this === {name:"B"}var fn1 = a.fn;fn1() // this === window
this:
作为构造函数执行:一般在实例化时确认;
作为对象属性执行:类似于上面的例子,一般时对象的属性值;
作为普通函数执行:一般是window
call apply bind:一般是会被改变this的指向;
function Foo(name){ this.name = name;//这里的this表示实例化的f的属性:f.name}var f = new Foo('zhangsan');=============================var obj = { name:"aa", printName:function(){ console.log(this.name);//这里的this表示obj }}obj.printName();=============================function fn(){ console.log(this); //this===window}fn();=============================function fn1(name,age){ alert(name); console.log(this);//下面使用的是call,所以改变了this的指向,指向了call的第一个对象}//fn1.call({x:1},'zhangsan',20);fn1.apply({x:1},['zhangsan',20]);//apply 和call类似,只不过第二个参数变成了数组==============================var fn2 = function(name,age){ //bind方法必须是函数表达式的形式 alert(name); console.log(this);//如果不做call applay或bind的操作,这里的this指向window}.bind({y:200});//bind改变this的指向fn2('zhangsan',20);
作用域:
//无块级作用域,所以外面的name可以拿到这个数据 if(true){ var name = "zhangsan"}console.log(name);==========//函数和全局作用域var a = 100;//全局作用域function fn(){ var a = 200;//函数作用域 console.log('fn',a);}function fn1(){ console.log('fn1',a);}console.log('global',a);//global 100fn();// fn 200fn1();// fn1 100
作用域链:自由变量一直往上找
//当前作用域没有定义的变量,即自由变量//注意的是定义的时候,而不是执行的时刻var a = 100;function F1(){ var b = 200; function F2(){ var c = 300; console.log(a); console.log(b); console.log(c); } F2();}F1(); //结果是 100 200 300
{ var a = 100;}console.log(a); //可以获取到afunction fn2(){ var a = 100;}fn2();console.log(a);//获取不到a,是函数内部的局部变量
4.3 创建10个<a>标签,点击的时候弹出来对应的序号
因为变量i放在了全局作用域,每次循环之执行后,都会覆盖之前的值。
而上述方法,每次循环都在一个函数体里,相当于局部作用域,i都是独立的。
5. 异步
5.1 同步和异步的区别是什么?分别举一个同步和异步的例子
5.2 一个关于setTimeout的笔试题;
5.3 前端使用异步的场景有哪些;
(1)定时任务:setTimeout setInterval
(2)网络请求: ajax请求,动态<img>标签
(3)事件绑定
例如:
console.log('start');var img = document.createElement('img');img.onload = function (){ console.log('loaded');//图片加载完才执行这里}console.log('end');
执行顺序为:
start--end--loaded
5.4 获取2017-02-01格式的日期(视频4-5)
5.5 获取随机数,要求是长度一致的字符串格式
5.6 写一个能遍历对象和数组的通用forEach函数
数组API:
forEach 遍历所有元素every 判断所有元素是否都符合条件some 判断是否有至少一个元素符合条件sort 排序map 对元素重新组装,生成新数组filter 过滤符合条件的元素
var arr = [1,2,3];arr.forEach((item,index)=>{ console.log(item);});==============var arr = [1,2,3,4];var result = arr.every((item,index)=>{ //用来判断所有的数组元素,都满足一个条件,只要一个不满足,则返回false if(item<4){ return true }})console.log(result);//false==============var arr = [1,2,3,4];var result = arr.some((item,index)=>{ //用来判断所有的数组元素,只要有一个满足条件即可 if(item<4){ return true }})console.log(result);//true===============var arr = [1,4,3,5,2];var arr2 = arr.sort((a,b)=>{ return a - b;//从小到大排序 return b - a;//从大到小排序})console.log(arr2); ===============//map和forEach不同在于可以返回生成一个新的数组var arr = [1,2,3,4];var arr2 = arr.map((item,index)=>{ return ''+item+''})console.log(arr2);//[ "1", "2", "3", "4" ]============//类似的使用forEach则不会返回新数组var arr = [1,2,3,4];var arr2 = arr.forEach((item,index)=>{ return ''+item+''})console.log(arr); // [1,2,3,4]console.log(arr2);//undefined=============//类似的使用filter 也可以返回一个新的数组var arr = [1,2,3,4];var arr2 = arr.filter((item,index)=>{ if(item>2){ return true; }})console.log(arr2);//[3,4]=============//对象apivar obj = { x:100, y:200, z:300}var key;for(key in obj){ if(obj.hasOwnProperty(key)){ //这里表示是obj的原生属性而不是集成父级 console.log(key,obj[key]); }}
forEach:
6.1 通用事件绑定
//简单来写var btn = document.getElementById('btn1');btn.addEventListener('click',function(event){ console.log('clicked')})//封装函数的形式function bindEvent(elem,type,fn){ elem.addEventListener(type,fn);}var a = document.getElementById('link1');bindEvent(a,'click',function(e){ e.preventDefault();//组织a标签的默认行为 alert('click');})
6.2 在一个不断动态增加<a>标签的区域,给a上绑定事件,如何做?
使用代理:也就是给包裹a标签的div增减点击的监听事件,如果点击的目标是a则触发事件。这样不用给每一项增加点击事件了。
var div1= document.getElementById('div1');div1.addEventListener('click',function(e){ var target = e.target; if(target.nodeName === "A"){ alert(target.innerHTML) }})
7 跨域。(所有的跨域请求必须经过信息提供方允许)
可以允许跨域的有三个标签:
<img src="xxx">, <link href="xxx">,<script src="xxx">
JSONP的工作原理:
注意几点:
1. 允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,
这样客户端就可以随意定制自己的函数来自动处理返回数据了。2. 请求服务端地址,会动态生成一个js文件,包含了一个客户端提供的回调函数。也就是在服务器端返回的回调函数 让其执行。在客户端定义改回调函数。
3 服务器端设置可以跨域:
response.setHeader("Access-Control-Allow-Origin","http://a.com,http://b.com"); //允许的域名 或者是*response.setHeader("Access-Control-Allow-Headers","X-Requested-With"); //在服务器端判断request来自Ajax请求(异步)还是传统请求(同步): response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); //请求方式response.setHeader("Access-Control-Allow-Credentials","true"); //接受跨域的cookies
8 书写ajax的基本原理;
要完整实现一个AJAX异步调用和局部刷新,通常需要以下几个步骤:
(1)创建XMLHttpRequest对象,也就是创建一个异步调用对象.
(2)创建一个新的HTTP请求,并指定该HTTP请求的方法、URL及验证信息.
(3)设置响应HTTP请求状态变化的函数.
(4)发送HTTP请求.
(5)获取异步调用返回的数据.
(6)使用JavaScript和DOM实现局部刷新.
var xhr = new XMLHttpRequest();xhr.open("GET","/api",false);xhr.onreadystatechange = function(){ //onreadystatechange 每次状态改变所触发事件的事件处理程序。 //这里是函数异步执行 if(xhr.readyState == 4){ if(xhr.status == 200){ //status 从服务器返回的数字代码,比如常见的404(未找到)和200(已就绪) alert(xhr.responseText); //responseText 从服务器进程返回数据的字符串形式。 } }}xhr.send(null);//只有在使用send()方法之后,XMLHttpRequest对象的readyState//属性值才会开始改变,也才会激发readystatechange事件,并调用函数。
对于XmlHttpRequest的两个方法,open和send,其中open方法指定了:
a、向服务器提交数据的类型,即post还是get。b、请求的url地址和传递的参数。c、传输方式,false为同步,true为异步。默认为true。如果是异步通信方式(true),客户机就不等待服务器的响应;如果是同步方式(false),客户机就要等到服务器返回消息后才去执行其他操作。我们需要根据实际需要来指定同步方式,在某些页面中,可能会发出多个请求,甚至是有组织有计划有队形大规模的高强度的request,而后一个是会覆盖前一个的,这个时候当然要指定同步方式。readyState 对象状态值 0 (未初始化) 对象已建立,但是尚未初始化(尚未调用open方法) 1 (初始化) 对象已建立,尚未调用send方法 2 (发送数据) send方法已调用,但是当前的状态及http头未知 3 (数据传送中) 已接收部分数据,因为响应及http头不全,这时通过responseBody和responseText获取部分数据会出现错误, 4 (完成) 数据接收完毕,此时可以通过通过responseXml和responseText获取完整的回应数据9. cokie 用于存储的缺点
1 存储量很小 只有4kb2 所有的http请求都会带着,会影响获取资源的效率3 api简单,需要封装才能使用 document.cookie="name="+username;10 localStorage 和 sessionStorage
- Html5专门为本地存储而设计,最大容量是5M
- API简单易用 localStorage.setItem(key,value),localStorage.getItem(key)
- 目前所有的浏览器中都会把localStorage的值类型限定为string类型
- localStorage在浏览器的隐私模式下面是不可读取的
- localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空
11 js 模块化的好处
比如上面三个js文件 逐层引用;
使用方式:
所以用到模块化:
12
commonjs是用在服务器端的,同步的,如nodejs
amd, cmd是用在浏览器端的,异步的,如requirejs和seajs其中,amd先提出,cmd是根据commonjs和amd基础上提出的。12.1 AMD模式:
使用方式:
12.2 CommonJS 规范
CommonJS 属于 node.js 模块化规范,现在被大量用于前端,原因:1 前端开发依赖的插件和库,都可以从npm中获取;2 构建工具的高度自动化,使得使用npm的成本非常低;3 CommonJS 不会异步加载JS,而是同步一次性的加载出来,
需要异步加载js 使用AMD
使用了npm之后建议使用commonJS