课程总结
变量类型和计算
题目
- JS中使用typeof 能得到哪些类型
- 何时使用=== 何时使用===
- JS 中有哪些内置函数
- JS 变量按照存储方式区分为哪些类型,并描述其特点
- 如何理解JSON
解答
JS中使用typeof 能得到哪些类型
何时使用=== 何时使用===
if (obj.a == null) {
//这里相当于obj.a===null || obj.a===undefined 简写形式
//这是jQuery 源码中推荐的写法
}
JS 中的内置函数
如何理解JSON
// JSON 只不过是一个JS对象而已
JSON.stringify({a: 10, b: 20});
JSON.parse('{"a":10,"b":20}');
变量类型
值类型 VS 引用类型
值类型
var a = 100;
var b = a;
a = 200;
console.log(b);
引用类型:对象、数组、函数
var a = {age: 200};
var b = a;
b.age = 21;
console.log(a.age);
typeof 运算符详解
变量计算--强制类型转换
字符串拼接
var a = 100 + 10; //110
var b = 100 + "10"; //10010
== 运算符
console.log(100 == "100") //true
console.log(0 == "") //true
console.log(null == undefined) //true
if 语句
逻辑计算
原型和原型链
题目
- 如何准确判断一个变量是
数组类型 - 写一个原型链继承的例子
- 描述new 一个对象的过程
- zepto(或其他框架)源码中如何使用原型链
解答
如何准确判断一个变量是数组类型
var arr = [];
console.log(arr instanceof Array);
console.log(typeof arr); //typeof 无法判断arr是否是数组
写一个原型链继承的例子
function Anaimal() {
this.eat = function () {
console.log("animal eat");
}
};
function Dog() {
this.bark = function () {
console.log("dog bark");
}
};
Dog.prototype = new Anaimal();
// 哈士奇
var hashiqi = new Dog();
console.log(hashiqi);
描述new 一个对象的过程
构造函数
function Foo(name, age) {
//this = {}; //this 变成空对象
this.name = name;
this.age = age;
this.calss = "class-1";
// return this; //默认有这一行
}
var f = new Foo("zhangsan", 20);
var f1 = new Foo("lisi", 20); //创建多个对象
构造函数--扩展
原型规则和示例
5条原型规则,原型规则是学习原型链的基础
- 所有的引用类型(数组、对象、函数),都具有对象特性,即可自由扩展属性(除了“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);
如果这个对象本身没有这个属性时,那么会去它的_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.alertName();
f.printName();
循环对象自身的属性
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 () {
alert(this.name);
};
// 创建实例
var f = new Foo("zhangsan");
f.printName = function () {
console.log(this.name);
};
// 测试
f.alertName();
f.printName();
f.toString(); //要去f.__proto__.__proto__中查找
instanceof
用于判断引用类型属于哪个构造函数的方法。
作用域和闭包
题目
- 说一下对变量提升的理解
- 说明this 几种不同的使用场景
- 创建10个a标签,点击的时候弹出来对应的序号
- 如何理解作用域
- 实际开发中闭包的应用
解答
函数声明与函数表达式的区别
fn();
function fn() { }; //函数声明
fn1(); //会报错
var fn1 = function () {}; //函数表达式
执行上下文
console.log(a); //undefined
var a = 100;
fn("zhangsan"); //"zhangsan",20
function fn(name, age) {
age = 20;
console.log(name, age);
var age;
};
- 范围:一段< script >或者一个函数
- 全局:变量定义、函数声明
- 函数:变量定义、函数声明,this,arguments
this
- this 要在执行时才能确认值,定义时无法确认
- 作为构造函数执行
- 作为对象属性执行
- 作为普通函数执行
- call apply bind
// 作为构造函数执行
function Foo(name) {
this.name = name;
};
var f = new Foo("zhangsan");
// 作为对象属性执行
var obj = {
name: "A",
printName: function () {
console.log(this.name);
}
}
obj.printName();
// 作为普通函数执行
function fn() {
console.log(this);
};
fn();
// call apply
function fn1(name, age) {
alert(name);
console.log(this);
};
fn1.call({x: 100}, "zhangsan", 20); //工作中常用这个
fn1.apply({x: 100}, ["zhangsan", 20]);
// bind 只能用函数表达式,函数声明会报错
var fn2 = function (name, age) {
alert(name);
console.log(this);
}.bind({y: 200});
fn2("zhangsan", 20);
作用域
- 没有块级作用域
- 只有函数和全局作用域
// 无块级作用域
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);
fn();
作用域链
var a = 100;
function fn() {
var b = 200;
//当前作用域没有定义的变量,即“自由变量”
console.log(a);
console.log(b);
};
fn();
另一个例子
var a = 100;
function F1() {
var b = 200;
function F2() {
var c = 300;
console.log(a); //自由变量
console.log(b); //自由变量
console.log(c);
};
F2()
};
F1();
闭包
函数作为返回值
function F1() {
var a = 100;
// 返回一个函数(函数作为返回值)
return function () {
console.log(a); // 自由变量,父作用域寻找
}
}
// f1 得到一个函数
var f1 = F1();
var a = 200; //一个函数的作用域,是它定义时候的作用域,而不是它执行时候的作用域
f1();
闭包的使用场景
- 函数作为返回值(上一个demo)
- 函数作为参数传递(自己思考)
函数作为参数传递
function F1() {
var a = 100;
return function () {
console.log(a);
}
}
var f1 = F1();
function F2(fn) {
var a = 200;
fn(); //定义时的作用域,而非执行时的作用域
}
F2(f1);
异步和单线程
题目
- 同步和异步的区别是什么?分别举一个同步和异步的例子
- 一个关于setTimeout的笔试题
- 前端使用异步的场景有哪些?
解答 同步和异步的区别是什么?
- 同步
会阻塞代码执行,而异步不会 - alert 是同步,setTimeout 是异步
什么是异步(对比同步)
什么是异步
console.log(100);
setTimeout(function () {
console.log(200);
}, 0);
console.log(300);
对比同步
console.log(100);
alert(200);
console.log(300);
何时需要异步
- 在可能发生等待的情况
- 等待过程中不能像(alert)一样阻塞程序执行
- 因此,所有的“等待情况”都需要异步
前端使用异步的场景
- 定时任务setTimeout、setInterval
- 网络请求:ajax请求,动态< img >加载
- 事件绑定
Ajax 请求代码示例
console.log(100);
$.get("./data.json", function (data) {
console.log(data);
});
console.log(300);
< img >加载示例
console.log("start");
var img = document.createElement("img");
img.onload = function () {
console.log("loaded");
};
img.src = "xxx.png";
console.log("end");
事件绑定示例
console.log("start");
document.getElementById("btn").addEventListener("click", function () {
alert("clicked");
});
console.log("end");
异步和单线程
因为javascript 是单线程的,才会有异步这个概念。
console.log(100);
setTimeout(function () {
console.log(200);
}); // 没写时间
console.log(300);
其它知识
题目
- 获取2017-06-10 格式的日期
- 获取随机数,要求是长度一致的字符串格式
- 写一个能遍历数组和对象的forEach 函数
解答
获取2017-06-10 格式的日期
function formatDate(dt) {
if (!dt) {
dt = new Date();
}
var year = dt.getFullYear();
var month = dt.getMonth();
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);
获取随机数,要求是长度一致的字符串格式
var random = Math.random();
random = random + "0000000000"; //后面加上10个零
random = random.slice(0, 10);
console.log(random);
写一个能遍历数组和对象的forEach 函数
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(obj, function (key, value) {
console.log(key, value);
});
日期
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.rondom();
数组API
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 true;
}
});
console.log(result);
some
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);
filter
var arr = [1, 2, 3];
var arr2 = arr.filter(function (item, index) {
// 通过某一个条件过滤数组
if (item >= 2) {
return true;
}
});
console.log(arr2);
对象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]);
}
}
JS-Web-API
回顾JS 基础知识
JS-Web-API
- 基础知识: ECMA 262标准 (这个标准是规定一些基础语法、规则,在这个规则上面,我们怎么去开发,怎么去弹出一个弹框)
- JS-Web-API: W3C标准(浏览器对JS的运行,既要遵循ECMA 262标准,又要遵循W3C标准)
总结
DOM 操作
文档对象模型:Dodument Object Model 题目
- DOM 是哪种基本的数据结构?
- DOM 操作的常用API 有哪些?
- DOM 节点的Attribute 和 property 有何区别?
解答
DOM 是哪种基本的数据结构?
- 树
DOM 操作的常用API 有哪些?
- 获取DOM 节点,以及DOM 的property 和 Attribute
- 获取父节点,获取子节点
DOM 节点的Attribute 和 property 有何区别?
property只是一个JS 对象的属性的修改Attribute是对html 标签属性的修改
DOM 的本质
XML
html 是 xml 的一种特殊类型
DOM 可以理解为:浏览器拿到的html代码,结构化一个浏览器能识别并且js可操作的一个模型而已。
DOM 节点操作
- 获取DOM 节点
- Prototype
- Attribute
获取DOM 节点
var div1 = document.getElementById("div"); //元素
var divList = document.getElementsByTagName("div"); //集合
var containerList = document.getElementsByClassName(".container"); //集合
var pList = document.querySelectorAll("p"); //集合
Prototype
var pList = document.querySelectorAll("p");
var p = pList[0];
console.log(p.style.width); //获取样式
p.style.width = "100px"; //修改样式
console.log(p.className); //获取class
p.className = ".para"; //修改class
// 获取nodeName 和 nodeType
console.log(p.nodeName);
console.log(p.nodeType);
Attribute
var pList = document.querySelectorAll("p");
var p = pList[0];
p.getAttribute("data-name");
p.setAttribute("data-name", "imooc");
p.getAttribute("style");
p.setAttribute("style", "font-size:30px");
DOM 结构操作
- 新增节点
- 获取父元素
- 获取子元素
- 删除节点
新增节点
var div1 = document.getElementById("div");
// 添加新节点
var p1 = document.createElement("p");
p1.innerHTML = "this is p1";
div1.appendChild(p1); //添加新创建的元素
// 移动已有节点
var p2 = document.getElementById("p2");
div1.appendChild(p2);
获取父元素和子元素
var div1 = document.getElementById("div");
var parent = div1.parentElement;
var child = div1.childNodes;
div1.removeChild(child[0]);
删除节点
var div1 = document.getElementById("div");
var child = div1.childNodes;
div1.removeChild(child[0]);
BOM 操作
BOM:Brower Object Model 题目
- 如何检测浏览器的类型
- 拆解URL 的各个部分
解答
如何检测浏览器的类型?
var ua = navigator.userAgent;
var isChrome = ua.indexOf("Chrome");
console.log(isChrome);
navigator
var ua = navigator.userAgent;
var isChrome = ua.indexOf("Chrome");
console.log(isChrome);
screen
console.log(screen.width);
console.log(screen.height);
location
console.log(location.href);
console.log(location.protocol);
console.log(location.pathname);
console.log(location.search);
console.log(location.hash);
console.log(location.host);
history
history.back();
history.forward();
事件
题目
- 编写一个通用的事件监听函数
- 描述事件冒泡流程
- 对于一个无限下拉加载图片的页面,如何给每个图片绑定事件
通用事件绑定
var btn = document.getElementById("btn");
btn.addEventListener("click", function (e) {
alert("clicked");
});
function bindEvent(elem, type, fn) {
elem.addEventListener(type, fn);
};
var a = document.getElementById("link");
bindEvent(a, "click", function (e) {
e.preventDefault();
alert("clicked");
});
完善通用事件绑定函数
function bindEvent(elem, type, selector, fn) {
if (fn == null) {
fn = selector;
selector = null;
}
elem.addEventListener(type, function (e) {
var target;
if (selector) {
target = e.target;
if (target.matches(selector)) {
fn.call(target, e);
}
} else {
fn(e);
}
});
}
事件冒泡
HTML 结构
<div id="div1">
<p id="p1">激活</p>
<p id="p2">取消</p>
<p id="p3">取消</p>
<p id="p4">取消</p>
</div>
<div id="div2">
<p id="p5">取消</p>
<p id="p6">取消</p>
</div>
script 结构
var p1 = document.getElementById("p1");
var body = document.body;
p1.addEventListener("click", function (e) {
// e.stopPropagation();
alert("激活");
});
body.addEventListener("click", function (e) {
alert("取消");
});
代理
事件冒泡的具体应用
<div id="div1">
<a href="#">a1</a>
<a href="#">a2</a>
<a href="#">a3</a>
<!--会随时新增更多 a 标签-->
</div>
script 结构
var div1 = document.getElementById("div1");
div1.addEventListener("click", function (e) {
var target = e.target;
if (target.nodeName === "A") {
alert(target.innerHTML);
}
});
使用代理
var div1 = document.getElementById("div1");
bindEvent(div1, "click", "a", function (e) {
console.log(this.innerHTML)
});
不使用代理
var div1 = document.getElementById("div1");
var a = document.getElementById("a1");
bindEvent(div1, "click", function (e) {
console.log(a.innerHTML)
});
Ajax和跨域
Ajax
var xhr = new XMLHttpRequest();
xhr.open("GET", "/api", false);
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
alert(xhr.responseText);
}
}
};
xhr.send(null);
什么是跨域
- 浏览器有同源策略,不允许ajax访问其他域接口。
协议、域名、端口,有一个不同就算跨域。
有三个标签允许跨域加载资源
- < img src=xxx>
- < link href=xxx>
- < script src=xxx>
三个标签使用的场景
JSONP
JSONP 原理
服务端设置http header
存储
题目
- 请描述下cookie、sessionStorage 和 localStorage 的区别?
cookie
- 本身用于客户端和服务端通信
- 但是它有本地存储的功能,于是就被“借用”
- 使用document.cookie=xxx获取和修改即可
cookie 用于存储的缺点
- 存储量太小,只有4kb
- 所有http请求都带着,会影响获取资源的效率
- API简单,需要封装才能用document.cookie=xxx
sessionStorage 和 localStorage
- HTML5专门为存储而设计,存储量5M
- API 简单易用
cookie、sessionStorage 和 localStorage 的区别
- 容量
- 是否会携带到ajax中
- API易用性
模块化
不使用模块化的情况
不使用模块化
代码
使用
使用模块化
AMD
使用 require.js
CommonJS
Webpack