JSLearn


JavaScript基础知识剖析

01 变量与原型

  • 01-01 变量类型和计算(1)
  • 01-02 变量类型和计算(2)
  • 01-03 变量类型和计算(3)-JSON的理解
  • 01-04 原型与原型链-构造函数
  • 01-05 原型规则和示例
  • 01-06 原型链
  • 01-07 instanceof
  • 01-08 知识点小结 & 解决问题

02

  • 02-01 作用域和闭包-执行上下文
  • 02-02 作用域和闭包-this
  • 02-03 作用域和闭包-作用域
  • 02-04 作用域和闭包-闭包
  • 02-05 知识点小结 & 解决问题

03

  • 03-01 异步和单线程-什么是异步
  • 03-02 异步和单线程-单线程
  • 03-03 其他知识点-日期和Math
  • 03-04 其他知识点-数组和对象的API

04

05

06

07

  • 07-01 上线回滚-上线回滚流程

08 JS算法

  • 08-01 JavaScript算法测试函数
  • 08-02 JavaScript算法-冒泡排序
  • 08-03 JavaScript算法-选择排序

09 函数应用

  • 09-01 JavaScript算法测试函数

JS小练习

  • JSDemo JS小程序
  • JDMenu 京东无延迟菜单
  • DatePicker组件开发
  • 手风琴效果开发

知识点学习

01-01

变量类型和计算(1)

  • JS中使用typeof能得到的哪些类型
  • 何时使用===何时使用 ==
  • JS中有哪些内置函数
  • JS变量按照存储方式区分为哪些类型,并描述其特点
  • 如何理解JSON

值类型

  • 从内存来说值类型是把每一个值存储在变量类型的每一个位置
var a = 100;
var b = a;
a = 200
console.log(b);//100

引用类型

  • 把a赋值*-成一个对象,a的位置是通过指针指向一个位置
  • 把b赋值成a,其实是定义一个b,b的指针指向了那个对象位置
  • 也就是有两份 age:20的对象
  • 对象的引用,就相当于复写一个对象,这两个对象之间相互独立
  • 引用类型:对象、数组、函数
var a ={age:20};
var b = a;
b.age = 21;
console.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 //funciton

变量计算-强制类型转换

  • 字符串拼接
var a = 100 + 10;//110
var b = 100 + '10';//10010
  • == 运算符
100 == '100' //true
0 == '' //true
null == undefined //true
  • if语句
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.acb); //true

//判断一个变量会被当做true还是false
var a = 100;
console.log(!!a);//true

01-02

变量类型和计算(2)

JS中使用typeof能得到的类型

//问题:JS中使用typeof能得到哪些类型
typeof undefined //undefined
typeof 'abc' // String
typeof 123 //number
typeof true //boolean
typeof {} //object
typeof [] //object
typeof null //object
typeof console.log //funciton
  • 总结来说typeof可以得到undefined、String、number、boolean可以区分值类型,但对于引用类型无法很细的区分,只能区分函数。
  • 尤其是typeof null object它是一个引用类型

何时使用 === 和 ==

//问题:何时使用===何时使用==

if (obj.a == null) {
  //这里相当于 obj.a === null || obj.a === undefined,简写形式
  //这是jquery源码中推荐的写法
}

JS中的内置函数

//问题:JS中有哪些内置函数----数据封装类对象
//作为构造函数的作用
Object
Array
Boolean
Number
String
Function
Date
RegExp
Error

JS按照存储方式区分变量类型

//JS 变量按照存储方式区分为哪些类型,并描述其特点

//值类型
var a = 10;
var b = a;
a = 11;
console.log(b);  // 10

//引用类型
var obj1 = {x:100}
var obj2 = obj1;
obj1.x = 200;
console.log(obj2.x); // 200
  • ES中,引用类型是一种数据结构,用于将数据和功能组织在一起

01-03

变量类型和计算(3)-理解JSON

//问题:如何理解JSON
//JSON只不过是一个JS对象
//JSON也是一个数据格式
JSON.stringify({a:10,b:20});
JSON.parse('{"a":10."b":20}')

01-04

原型与原型链-构造函数

  • 如何准确判断一个变量数组类型
  • 写一个原型链继承的例子
  • 描述new一个对象的过程
  • zepto(或其他框架)源码中如何使用原型链

知识点

  • 构造函数
  • 构造函数-扩展
  • 原型规则和示例
  • 原型链
  • instanceof

构造函数

  • 自己的想法
  • 普通的函数就像是按步骤执行的动作,而构造函数更像是可更改零件的木偶,普通函数可以直接调用,但是构造函数需要new
  • 因为构造函数也是函数,所以可以直接被调用,但是它的返回值为undefine,此时构造函数里面的this对象等于全局this对象
  • 扩展实例和对象的区别,从定义上来讲:1、实例是类的具象化产品,2、而对象是一个具有多种属性的内容结构。
funciton 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 a = [] 其实是 var a = new Array()的语法糖
  • function Foo(){...}其实是 var Foo = new Function(...)
  • 使用 instanceof 判断一个函数是否是一个变量的构造函数
    • 如果想判断一个变量是否为“数组”:变量 instanceof Array

01-05

原型规则和示例

  • 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解释为JavaScript开发函式库及框架
  • 所有的函数,都有一个prototype(显示原型)属性,属性值也是一个普通对象。
console.log(fn.prototype);

第4条

  • 所有引用类型(数组、对象、函数),__proto__属性值指向它的构造函数的prototype属性值
console.log(obj.__proto__ === Object.prototype);

第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();
f.alertName();
  • this

循环对象自身属性

var item;
for (item in f) {
  //高级浏览器已经在for in 中屏蔽了来自原型的属性
  //但是这里建议大家还是加上这个判断,保证程序的健壮性
  if(f.hasOwnProperty(item)) {
    console.log(item);
  }
}

01-06

原型链

//构造函数
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();
f.alertName();
f.toString(); // 要去f.__proto__.__proto__中查找

原型链视图

原型链图
原型链图

01-07

instanceof

  • 用于判断引用类型属于哪个构造函数的方法
  • f instanceof Foo 的判断逻辑是:
  • f__proto__一层一层往上走,是否能对应到Foo.prototype
  • 再试着判断f instanceof Object

01-08

知识点小结 & 解决问题

如何准确判断一个变量是数组类型

var arr = [];
arr instanceof Array; //true
typeof arr //object  typeof是无法判断是否是数组

写一个原型链继承的例子

//动物
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();
//如果要真正写,就要写更贴近实战的原型链

描述new一个对象的过程

  • 创建一个新对象
  • this指向这个新对象
  • 执行代码,即对this赋值
  • 返回this 🔙
function Foo(name,age){
  this.name = name ;
  this.age = age ;
  //return this //默认有这一行
}
var f = new Foo('zhangsan',20);
//var f1 = new Foo('list',22) //创建多个对象

zepto(或其他框架)源码中如何使用原型链

  • 。。。。。。

贴近实际开发原型链继承的例子

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) ;
}

var div1 = new Elem('div1');
//console.log(div1.html());
div1.html('<p>hello imooc</p>')
div1.on('click',function () {
  alert('click')
})

02-01

作用域和闭包-执行上下文

  • 说一下对变量提升的理解
  • 说明this几种不同的使用场景
  • 创建10个<a>标签,点击的时候弹出来对应的序号
  • 如何理解作用域
  • 实际开发中闭包的应用

知识点梳理

  • 执行上下文
  • this
  • 作用域
  • 作用域链
  • 闭包

执行上下文

console.log(a);  // undefined
var a = 100;

fn('zhangsan')  // 'zhangsan' 20
function fn(name) {
  age = 20;
  console.log(name, age);
  var age;
}
  • 范围:一段<script>或者一个函数
  • 全局:变量定义、函数声明
  • 函数:变量定义、函数声明、this、arguments
  • 注意⚠️“函数声明”和“函数表达式”的区别
fn()
function fn() {
  //声明
}

fn1()
var fn1 = function () {
  //表示
}
var a = 100; //类似于这个

//全局声明

console.log(a);
var a = 100;

fn('zhangsan')
function fn(name) {
  console.log(this);
  age = 20;
  console.log(name,age);
  var age;

  bar(100);

  function bar(num) {
    console.log(num);
  }
}

02-01

作用域和闭包-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
  • 作为构造函数执行
  • 作为对象属性执行
  • 作为普通函数执行
  • 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 bind
function fn1(name) {
  alert(name);
  console.log(this);
}
fn1.call({x:100},'zhangsan',20);
// bind
var fn2 = function fn2(name) {
  alert(name);
  console.log(this);
}.bind({y:200});
fn2('zhangsan',20);

02-03

作用域和闭包-作用域

作用域

  • 没有块级作用域
  • 只有函数和全局作用域
//无块级作用域
if(true){
  var name = 'zhangsan';
}
console.log(name);

//函数和全局作用域
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);//a是自由变量。形成一个链式结构,向父级去查找
    console.log(b);//b是自由变量
    console.log(c);//
  }
}

02-04

作用域和闭包-闭包

  • 函数作为返回值
function F1() {
  var a = 100;
  //返回一个函数(函数作为返回值)
  return function () {
    console.log(a);//自由变量,父作用域中查找
  }
}
//f1得到一个函数
var f1 = F1();
var a = 200;
f1();
  • 函数作为参数传递
function F1() {
  var a = 100;
  return function () {
    console.log(a);  //自由变量,父作用域中查找
  }
}
var f1 = F1();
function F2(fn) {
  var a = 200;
  fn();
}
F2(f1);

02-05

知识点小结 & 解决问题

对变量提升的理解

  • 变量定义
  • 函数声明(注意和函数表达式的区别)

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 bind
function fn1(name) {
  alert(name);
  console.log(this);
}
fn1.call({x:100},'zhangsan',20);
// bind
var fn2 = function fn2(name) {
  alert(name);
  console.log(this);
}.bind({y:200});
fn2('zhangsan',20);

创建10个<a>标签 点击的时候弹出来对应的序号

  • 错误写法
//这是一个错误的写法!!!
var i,a;
for (var i = 0; i < 10; i++) {
  a = document.createElement('a');
  a.innerHTML = i + '<br>';
  a.addEventListener('click',function (e) {
    e.preventDefault();
    alert(i)
  })
  document.body.appendChild(a);
}
//输出为如下: <a>"9"<br></a>
  • 正确写法
//这是一个正确写法!!!
var i;
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)
}

如何理解作用域

  • 自由变量
  • 作用域链,即自由变量的查找
  • 闭包的两个场景

实际开发中闭包的应用

//闭包实际应用中主要作用于封装变量,收取权限
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

03-01

异步和单线程-什么是异步

  • 同步和异步的区别是什么?分别举一个同步和异步的例子
  • 一个关于setTimeout的笔试题
  • 前端使用异步的场景有哪些

异步知识点

  • 什么是异步(对比同步)
  • 前端使用异步的场景
  • 异步与单线程

什么是异步

console.log(100); // step1
setTimeout(function () {
  console.log(200); // step3
},1000);
console.log(300); // step2

对比同步

console.log(100);
alert(200) // 1秒钟后点击确认
console.log(300);

何时需要异步

  • 在可能发生等待的情况
  • 等待过程中不能像alert一样阻塞程序运行
  • 因此,所有的所有的等待情况都需要异步

前端使用异步的场景

  • 定时任务:setTimeout,setInverval
  • 网络请求:ajax请求,动态<img>加载
//ajax请求
console.log('start');
$.get('./data1.json',function (data1) {
  console.log(data1);
})
console.log('end');
//<img>加载示例
console.log('start');
var img = document.createElement('img');
img.onload = function () {
  console.log('loaded');
}
img.src = '/xxx.png';
console.log('end');
  • 事件绑定

03-02

异步和单线程-单线程

console.log(100); // step1
setTimeout(function () {
  console.log(200); // step3
});
console.log(300); // step2
  • 从上面代码中理解单线程
    • 执行第一行,打印100
    • 执行setTimeout后,传入setTimeout的函数会被暂存起来,不会立即执行(单线程的特点,不能同时干两件事)
    • 执行最后一行打印300
    • 待所有程序执行完,处于空闲状态时,会立马看有没有暂存起来的要执行
    • 发现暂存起来的setTimeout中的函数无需等待时间,就立即来过来执行

解答:异步与单线程

  • 同步和异步的区别是什么?分别举一个同步和异步的例子
    • 同步会阻塞代码执行,而异步不会
    • alert是同步,setTimeout是异步
  • 一个关于setTimeout的笔试题
  • 可以说setTimeout是等待页面加载完毕后,在进行加载
console.log(1);
setTimeout(function () {
  console.log(2);
},0)
console.log(3);
setTimeout(function () {
  console.log(4);
},1000)
console.log(5);
  • 前端使用异步的场景有哪些
    • 定时任务:setTimeout,setInverval
    • 网络任务:ajax请求,动态<img>加载
    • 事件绑定

03-03

其他知识点-日期和Math

获取 2017-06-10 格式的日期

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()

03-04

其他知识点-数组和对象的API

写一个能遍历对象和数组的通用forEach函数

数组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 functionName(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]);
  }
}
  • 举个例子
<!DOCTYPE html>
<html>
    <head>
    <meta charset="utf-8" />
        <title>Register</title>
        <meta name="viewport" content="width=device-width,initial-scale=1,minimum-scale=1,maximum-scale=1,user-scalable=no" />
  </head>
<body>
  <script type="text/javascript">
    console.log(Date.now());
    var dt = new Date();
    console.log(dt);
    console.log(dt.getTime());
    console.log(dt.getFullYear());
    console.log(dt.getDate());

    var arr = [1,2,3,4]

    arr.forEach(function (item,index) {
      console.log(index,item);
    })
  </script>
</body>
</html>

问题解答

  • 获取2017-06-10格式的日期
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);
  • 获取随机数,要求是长度一致的字符串格式
var random = Math.random();
var random = random + '0000000000'; //后面加上10个0
var random = random.slice(0,10);
console.log(random);
  • 写一个能遍历对象和数组的通用forEach函数
//do
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);
})

//init
function forEach(obj,fn) {
  var key;
  if (obj instanceof Array) {
    //准确判断是不是一个数组
    obj.forEach(function (index.item) {
      fn(index,item);
    })
  }else {
    //不是数组就是对象
    for (key in obj){
      fn(key,obj[key]);
    }
  }
}

04-01

从基础知识到JS-Web-API

  • 变量类型和计算
  • 原型和原型链
  • 闭包和作用域
  • 异步和单线程
  • 其他(如日期、Math、各种常用API)

特点

  • 特点:表面上来看不能用于工作中开发代码
  • 内置函数:Object Array Boolean String ......
  • 内置对象:Math JSON ...
  • 我们连在网页弹出一句Hello World都不能实现

JS-Web-API

  • JS基础知识:ECMA 262标准
  • JS-Web-API:W3C标准
  • W3C标准中关于JS的规定有:
    • DOM操作
    • BOM操作
    • 事件绑定
    • ajax请求(包含http协议)
    • 存储

基本操作

  • 页面弹框是windows.alert(123),浏览器需要做:
    • 定义一个windows全局变量,对象类型;
    • 给它定义一个alert属性,属性值是一个函数;
  • 获取元素document.getElementById(id),浏览器需要:
    • 定义一个document全局变量,对象属性;
    • 给它定义一个getElementById的属性,属性值是一个函数;
  • W3C标准没有规定任何JS基础相关的东西;
  • 不管什么变量类型、原型、作用域和异步
  • 只管定义用于浏览器中JS操作页面的API和全局变量
  • 全面考虑,JS内置的全局函数和对象有哪些?
  • 之前ECMA的
  • 比如 window document
  • 所有未定义的全局变量,如navigator.userAgent

总结

  • 常说的JS(浏览器执行的JS)包含两个部分:
  • JS基础知识(ECMA262标准);
  • JS-Web-API(W3C标准);

04-02

DOM操作

  • Document Object Model
  • DOM是哪种基本的数据结构
  • DOM操作的常用API有哪些
  • DOM节点的attr和property有和区别

DOM的本质

  • XML
<?xml version="1.0" encoding="UTF-8"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Dont forget me this weekend</body>
<other>
<a></a>
<b></b>
</other>
</note>
  • XML
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Document</title>
</head>
<body>
  <div>
    <p>this is p</p>
  </div>
</body>
</html>

04-03

DOM节点操作

  • 获取DOM节点
  • prototype,获取JS对象上的属性
  • Attribute,获取DOM标签上的属性

获取DOM节点

var div1 = document.getElementById('div1'); //元素
var divList = document.getElementByTagName('div'); //集合
console.log(divList.length);
console.log(divList[0]);

var containerList = document.getElementByClassName('.container'); //集合
var pList = document.querySelectorAll('p'); //集合

property

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 = 'p1' //修改class

// 获取 nodeName 和 ndoeType
console.log(p.nodeName);
console.log(p.nodeType);

Attribute

var pList = document.querySelectorAll('p');
var p = pList[0];
p.getAttribute('data-name');
p.getAttribute('data-name','imooc');
p.getAttribute('style');
p.setAttribute('style','font-size:30px;');

04-04

DOM结构操作

  • 新增节点
var div1 = document.getElementById('div1');
//添加新节点
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('div1');
var parent = div1.parentElement;
  • 删除节点
var div1 = document.getElementById('div1');
var child = div1.childNodes;
div1.removeChild(child[0]);

举个栗子(例子:example)!!!

<!DOCTYPE html>
<html>
<head>
</head>
<body>
  <div id="div1">
    <p id="p1">this is p1</p>
    <p id="p2">this is p2</p>
  </div>
  <div id="div2">
    <p id="p3">this is p3</p>
    <p id="p4">this is p4</p>
  </div>
  <script type="text/javascript">
  // 1.
  // var p = document.createElement('p');
  // p.innerHTML = 'new p';
  // var div1 = document.getElementById('div1');
  // div1.appendChild(p);
  // 2.移动P4到div1中
  var p4 = document.getElementById('p4');
  var div1 = document.getElementById('div1');
  div1.appendChild(p4);
  console.log(p4.parentElement);
  console.log(div1.parentElement);
  console.log(div1.childNodes);
  console.log(div1.childNodes[0].nodeType); //text 3
  console.log(div1.childNodes[1].nodeType); //p    1
  </script>
</body>
</html>

04-05

DOM知识解答

  • DOM是哪种基本的数据结构?
  • DOM操作的常用API有哪些
    • 获取DOM节点,以及节点的propertyAttribute
    • 获取父节点,获取子节点
    • 新增节点,删除节点
  • DOM节点Attributeproperty有何区别
    • property只是一个JS对象的属性的修改
    • Attribute是对html标签属性的修改
  • 重点总结
    • DOM本质
    • DOM节点的操作
    • DOM结构操作

04-06

BOM操作

  • Browser Object Model

如何监测浏览器的类型

拆解url的各部分

知识点

  • navigator & screen
//navigator
var ua = navigator.userAgent;
var isChrome = ua.indexOf('Chrome');
console.log(isChrome);
//screen
console.log(screen.width);
console.log(screen.height);
  • location & history
//location
console.log(location.href);
console.log(location.protocel);
console.log(location.pathname);
console.log(location.search);
console.log(location.hash);
//history
history.back();
history.forward();

05-01

编写一个通用的事件监听函数

描述事件冒泡流程

* DOM树形结构
* 事件冒泡
* 阻止冒泡
* 冒泡的应用

对于一个无线下拉加载图片的页面,如何给每个图片绑定事件

* 使用代理
* 知道代理的有点
通用事件绑定
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(); //阻止默认行为
  alert('clicked');
});
  • 关于IE低版本的兼容性
    • IE低版本使用attachEvent绑定事件,和W3C标准不一样
    • IE低版本使用量非常少,很多网站早已不支持
    • 建议对IE低版本的兼容性:了解即可,无需深究
    • 如果遇到对IE低版本要求苛刻的面试,果断放弃

事件冒泡

<body>
  <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>
</body>
var p1 = document.getElementById('p1');
var body = document.body;
bindEvent(p1,'click',function (e) {
  e.stopPropatation();
  alert('激活');
});
bindEvent(body,'click',function(e){
  alert('取消');
})

代理

<div id="div1">
  <a href="#">a1</a>
  <a href="#">a2</a>
  <a href="#">a3</a>
  <a href="#">a4</a>
  <!-- 会随时新增更多a标签 -->
</div>
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);
})
function bindEvent(elem,type,selector,fn) {
  if (fn == null) {
    fn = selector;
  }
  elem.addEventListener(type,function (e) {
    var target;
    if (selector) {
      target = e.target;
      if (target.matches(selector)) {
        fn.call(target,e);
      }
    }else {
      fn(e);
    }
  })
}

05-02

Ajax-XMLHttpRequest

  • 手动编写一个ajax,不依赖第三方库
  • 跨域的几种实现方式

知识点

XMLHttpRequest
var xhr = new XMLHttpRequest();
xhr.open("GET","/api",false)
xhr.onreadystatechange = function () {
  //这里的函数异步执行,可参考之前JS基础的异步模块
  if(xhr.readyState == 4){
    if (xhr.status == 200) {
      alert(xhr.responseText)
    }
  }
}
xhr.send(null);
* IE低版本使用ActiveXObject,和W3C标准不一样
* IE低版本使用量已经非常少,很多网站早已不支持IE低版本
* 建议对IE低版本的兼容性:了解即可,无需深究
状态码
xhr.onreadystatechange = function () {
  //这里的函数异步执行,可参考之前JS基础的异步模块
  if(xhr.readyState == 4){
    if (xhr.status == 200) {
      alert(xhr.responseText)
    }
  }
}
  • readyState
    • 0-(未初始化)还没有调用send()方法
    • 1-(载入)已调用send()方法,正在发送请求
    • 2-(载入完成)send()方法执行完成,已经接收到全部响应内容
    • 3-(交互)正在解析响应内容
    • 4-(完成)响应内容解析完成,可以在客户端调用
  • status
    • 2XX-表示成功处理请求。如200
    • 3XX-需要重定向,浏览器直接跳转
    • 4XX-客户端请求错误,如404
    • 5XX-服务端错误
跨域
  • 什么时跨域
    • 浏览器有同源策略,不允许ajax访问其他域接口
    • http://www.yourname.com/page1.html
    • http://m.imooc.com/course/ajaxcourserecom?cid=459
    • 跨域条件:协议、域名、端口、有一个不同就算跨域
      • 但是有三个标签允许跨域加载资源
      • <img src=XXX>
      • <link href=XXXX>
      • <script src=XXX>
    • 三个标签的场景
      • <img>用于打点统计,统计网站可能是其他域
      • <link><script>可以使用CDN,CDN的也是其他域
      • <script>可以用于JSONP
    • 跨域注意事项
      • 所有的跨域请求都必须经过信息提供方允许
      • 如果未经允许即可获得,那是浏览器同源策略出现漏洞
  • JSONP
    • 加载 http://coding.m.imooc.com/classindex.html

    • 不一定服务器端真正有一个classindex.html文件

    • 服务器可以根据请求,动态生成一个文件,返回

    • 同理与<script src="http://coding.m.imooc.com/api.js">

    • 假如你的网站要跨域访问慕课网的一个接口

    • 给你一个地址http://coding.m.imooc.com/api.js

    • 返回内容格式如callback({x:100,y:200})(可动态生成)

<script>
window.callback = function (data) {
  //这是我们跨域的到信息
  console.log(data);
}
</script>
<script src="http://coding.m.imooc.com/api.js"></script>
<!-- 以上将返回 callback({x:100,y:200}) -->
  • 服务器端设置http header
    • 另外一个解决跨域的简洁方法,需要服务器来做
    • 但是作为交互方,我们必须知道这个方法
    • 是将来解决跨域问题的一个趋势
//注意:不同后端语言的写法可能不一样

//第二个参数填写允许跨域的域名称,不建议直接写 “*”
response.setHeader("Access-Control-Allow-Origin","http://a.com, http://b.com");
response.setHeader("Access-Control-Allow-Header","X-Requested-With");
response.setHeader("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");

//接收跨域的cookie
response.setHeader("Access-Control-Allow-Credentials","true");

05-03

存储

  • 请描述一下cookie,sessionStoragelocalStorage的区别?

cookie

  • 本身用于客户端和服务端通信
  • 但是它有本地存储的功能,于是就被借用
  • 使用document.cookie = ... 获取和修改即可
cookie用于存储的缺点
  • 存储量小,只有4kb
  • 所有http请求都带着,会影响获取资源的效率
  • API简单,需要封装才能用document.cookie = ...

localStorage和sessionStorage

  • HTML5专门为存储设计,最大容量5M
  • API简答易用:
  • localStorage.setItem(key,value);localStorage.getItem(key);
  • sessionStorage关闭浏览器会清理
  • iOS safari 隐藏模式下,localStorage.getItem会报错
  • 建议统一使用try-catch封装

cookie sessionStorage localStorage 的区别

  • 容量
  • 是否会携带到ajax中
  • API易用性

06-01

模块化

  • 不使用模块化
  • 使用模块化
  • AMD
  • CommonJS

不使用模块化

  • util getFormatDate函数
  • a-util.js aGetFormatDate函数 使用getFormatDate
  • a.js aGetFormatDate
  • 定义
//util.js
function getFormatDate(date,type) {
  //type === 1返回 2017-06-15
  //type === 2返回 2017年6月15日 格式
  //...
}
//a-util.js
function aGetFormatDate(data) {
  //返回
  return getFormatDate(date,2);
}
// a.js
var dt = new Date()
console.log(aGetFormatDate(dt));
  • 使用
<script src="util.js"></script>
<script src="a-util.js"></script>
<script src="a.js"></script>
<!-- 1.这些代码中的函数必须是全局变量,才能暴露给使用方。全局变量污染 -->
<!-- 2. a.js 知道要引用 a-util.js ,但是他知道还需要依赖于util.js吗? -->

使用模块化

//util.js
export{
  getFormatDate:function (data,type) {
    //type === 1 返回 2017-06-15
    //type === 2 返回 2017年6月15日 格式
  }
}
//a-util.js
var getFormatDate = require('util.js');
export{
  aGetFormatDate:function (date) {
    //要求返回 2017年6月15日 格式
    return getFormatDate(date,2);
  }
}
// a.js
var aGetFormatDate = require('a-util.js')
var dt = new Date();
console.log(aGetFormatDate(dt));

//直接‘<script src="a.js"></script>’,其他的根据依赖关系自动引用
//那两个函数,没必要做成全局变量,不会带来污染和覆盖

06-02

AMD

  • require.js requirejs.org/
  • 全局define函数
  • 全局require函数
  • 依赖JS会自动、异步加载
//util.js
define(function () {
  return{
    getFormatDate: function (date,type) {
      if (type === 1) {
        return '2017-06-15'
      }
      if (type === 2) {
        return '2017年6月15日'
      }
    }
  }
});

//a-util.js
define(['./util.js'],function (util) {
  return{
    aGetFormatDate: function (date) {
      return util.getFormatDate(date,2);
    }
  }
});

// a.js
define('[./a-util.js]',function (aUtil) {
  return{
    printDate:function (date) {
      console.log(aUtil.aGetFormatDate);
    }
  }
});

//main.js
require('[./a.js]',function (a) {
  var date = new Date();
  a.printDate(date);
});
  • 使用
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Document</title>
</head>
<body>
  <p>AMD test</p>
  <script src="/require.min.js" data-main="./main.js"></script>
</body>
</html>

06-03

CommonJS

  • nodejs模块化规范,现在被大量用于前端,原因:
    • 前端开发依赖的插件和库,都可以从npm中获取
    • 构建工具的高度自动化,是的使用npm的成本非常低
    • CommonJS不会异步加载JS,而是同步一次性加载出来
module.exports = {
  getFormatDate:function (data,type) {
    if (type === 1) {
      return '2017-06-15';
    }
    if (type === 2) {
      return '2017年6月15日';
    }
  }
}

// a-util.js
var util = require('util.js')
module.exports = {
  aGetFormatDate:function (data) {
    return util.getFormatDate(data,2);
  }
}

AMD和CommonJS的使用场景

  • 需要异步加载JS,使用AMD
  • 使用了npm之后建议使用CommonJS

07-01

上线回滚-上线回滚流程

  • 上线和回滚的基本流程
  • linux基本命令

上线回滚流程

  • 重要的开发环节

上线流程要点

  • 将测试完的代码提交到git版本库的master分支
  • 将当前服务器的代码全部打包并记录版本号,备份
  • 将master分支的代码提交覆盖到线上服务器,生成新的版本号

回滚流程要点

  • 将当前服务器的代码打包并记录版本号,备份
  • 将备份的上一个版本号解压,覆盖到线上服务器,并生成新的版本号

Linux基本命令

  • 服务器使用Linux居多,server版,只有命令行
  • 测试环境要匹配线上环境,因此也是Linux
  • 经常需要登陆测试机来自己配置、获取数据

08-01

JavaScript算法测试函数

  • SetData()函数生成了存储在数组中的随机数字。Math类的random()函数会生成[0,1)区间内的随机数字。换句话说,random()函数生成的随机数字大于等于0,但不会等于1。最后在用Math类的floor()函数确定最终结果。
  • 如下这个公式可以成功生成1~100的随机数字集合。

function CArray(numElements) {
  this.dataStore = [];
  this.pos = 0;
  this.numElements = numElements;
  this.insert = insert;
  this.toString = toString;
  this.clear = clear;
  this.setData = setData;
  this.swap = swap;
  for (var i = 0; i < numElements; ++i) {
    this.dataStore[i] = i;
  }
}
//数据输出
function setData() {
  for (var i = 0; i < this.numElements; ++i) {
    this.dataStore[i] = Math.floor(Math.random() * (this.numElements + 1));//生成随机数组
  }
}

function clear() {
  for (var i = 0; i < this.dataStore.length; ++i) {
    this.dataStore[i] = 0;
  }
}

function insert(element) {
  this.dataStore[this.pos++] = element;
}

function toString() {
  var restr = "";
  for (var i = 0; i < this.dataStore.length; ++i) {
    restr += this.dataStore[i] + " ";
    if (i > 0 & i % 10 == 0) {
      restr += "\n";
    }
  }
  return restr;
}

function swap(arr,index1,index2) {
  var temp = arr[index1];
  arr[index1] = arr[index2];
  arr[index2] = temp;
}

//测试
var numElements = 100;
var myNums = new CArray(numElements);
myNums.setData();
console.log(myNums.toString());

<p align="center">

</p>

名词解释:

  • n: 数据规模
  • k:“桶”的个数
  • In-place: 占用常数内存,不占用额外内存
  • Out-place: 占用额外内存
  • 稳定性:排序后2个相等键值的顺序和排序之前它们的顺序相同

08-02

JavaScript算法-冒泡排序

  • 冒泡排序
  • 最慢的排序算法之一
  • 冒泡排序,之所以这么叫是因为使用这种排序算法排序时,数据值就会像气泡一样从数组的一端漂浮到另一端。假设正在将一组数字按照升序排列,较大的值会浮动到数组的右侧,而较小的值会浮动到数组的左侧。之所以会产生这种现象是因为算法会多次在数组中移动,比较相邻的数据,当左侧值大于右侧值时将它们进行互换。

<p align="center">

</p>


function bubbleSort() {
  var numElements = this.dataStore.length;
  var temp;
  for (var outer = numElements; outer >= 2; --outer) {
    for (var inner = 0; inner <= outer - 1; ++inner ) {
      if (this.dataStore[inner] > this.dataStore[inner + 1]) {
        swap(this.dataStore,inner,inner + 1);
      }
    }
  }
}
  • 使用bubbleSort()对10个数字排序
var numElements = 10;
var mynums = new CArray(numElements);
mynums.setData();
console.log(mynums.toString());
mynums.bubbleSort();
console.log(mynums.toString);

08-03

JavaScript算法-选择排序

  • 选择排序

  • 选择排序从数组的开头开始,将第一个元素和其他元素进行比较。检查完所有元素后,最小的元素会被放到数组的第一个位置,然后算法会从第二个位置继续。这个过程一直进行,当进行到数组的倒数第二个位置时,所有的数据便完成了排序。

  • 选择排序会用到嵌套循环。外循环从数组的第一个元素一定到倒数第二个元素;内循环从第二个数组元素移动到最后一个元素,查找比当前外循环

<p align="center">

</p>


09-01

JS基本应用-函数

  1. 函数声明与函数表达式、对象实例化的区别
 add1(1,1);
 add2(1,2);
 add3(1,3);
 function add1(i, j){
   console.log(i+j);
 }
 var add2 = function(i, j){
   console.log(i+j);
 }
 var add3 = new Function("i", "j", "console.log(i+j);");
  1. 对象实例化与函数声明与函数表达式的区别
 (function(){
   var i = 10;
   function add(j) {
     console.log(i+j);
     debugger;
   }
   add(1);
 })();

 (function(){
   var i = 10;
   var add = new Function("j", "console.log(i+j);debugger;");
   add(1);
 })();
  1. bind的使用
 function Point(x, y){
     this.x = x;
     this.y = y;
 }
 Point.prototype.move = function(x, y) {
     this.x += x;
     this.y += y;
 }
 var p = new Point(0,0);
 var circle = {x:1, y:1, r:1};
 var circleMove = p.move.bind(circle, 2, 1);
 circleMove();
  1. 构造函数
 function Car(type,color){
   this.type = type;
   this.color = color;
   this.status = "stop";
   this.light = "off";
 }
 Car.prototype.start = function(){
   this.status = "driving";
   this.light = "on";
   console.log(this.type + " is " + this.status);
 }
 Car.prototype.stop = function(){
   this.status = "stop";
   this.light = "off";
   console.log(this.type + " is " + this.status);
 }
 var audi = new Car("audi", "silver");
 var benz = new Car("benz", "black");
 var ferrari = new Car("ferrari", "yellow");
  1. 函数调用模式
 function add(i, j){
   return i+j;
 }
 var myNumber = {
   value: 1,
   double: function(){
     var helper = function(){
       this.value = add(this.value,this.value);
     }
     helper();
   }
 }
  1. arguments转数组
 function add(i, j) {
   var args = Array.prototype.slice.apply(arguments);
   args.forEach(function(item){
     console.log(item);
   })
 }
 add(1,2,3);
  1. arguments.callee使用
 console.log(
   (function(i){
     if (i==0) {
       return 1;
     }
     return i*arguments.callee(i-1);
   })(5)
 );
  1. 递归
 function factorial(i){
   if (i==0) {
     return 1;
   }
   return i*factorial(i-1);
 }
  1. 普通递归函数跟记忆函数调用次数对比
 var factorial = (function(){
   var count = 0;
   var fac = function(i){
     count++;
     if (i==0) {
       console.log('调用次数:' + count); 
       return 1;
     }
     return i*factorial(i-1);
   }
   return fac;
 })();
 for(var i=0;i<=10;i++){
   console.log(factorial(i)); 
 }

//记忆函数
 var factorial = (function(){
   var memo = [1];
   var count = 0;
   var fac = function(i){
     count++;
     var result = memo[i];
     if(typeof result === 'number'){
       console.log('调用次数:' + count); 
       return result;
     } 
     result = i*fac(i-1);
     memo[i] = result;
     return result;
   }
   return fac;
 })();
 for(var i=0;i<=10;i++){
   console.log(factorial(i)); 
 }
  1. curry 函数柯里化
  • 把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术
 function add(value){
    var helper = function(next){
       value = typeof(value)==="undefined"?next:value+next;
       return helper;
    }
    helper.valueOf = function(){
      return value;
    }
    return helper
 }

JSDemo JS小程序

JDMenu 京东无延迟菜单

1.开发普通二级菜单

  • 事件代理方式进行绑定
  • mouseentermouseover的区别:
  • 使用mouseover/mouseout时候,如果鼠标移动到子元素上,即便没有离开父元素,也会触发父元素的mouseout事件;
  • 使用mouseenter/mouseleave时,如果鼠标没有离开父元素,在其子元素上任意移动,也不会触发mouseleave事件;

2.加入延迟优化

  • 切换子菜单的时候,用setTimeout设置延迟
  • debounce去抖o((⊙﹏⊙))o.技术:
  • 在事件被频繁触发时买只执行一次

3.基于用户行为预测的切换技术

  • 跟踪鼠标的移动
  • 用鼠标当前位置,和鼠标上一次位置与子菜单上下边缘形成的三角区域进行比较

DatePicker组件开发

1.基础页面制作

  • 标头
  • 身体

2.数据部分

  • 渲染当月日历表格
  • 用于点击时取日期值
日期对象
  • newDate(year,month-1,date)
  • 月份需要-1
  • 越界自动进退位
  • getFullYear()/getMonth()/getDate()
  • getDay()获取当前日期是周几?
    转自github
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,185评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,652评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,524评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,339评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,387评论 6 391
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,287评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,130评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,985评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,420评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,617评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,779评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,477评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,088评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,716评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,857评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,876评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,700评论 2 354

推荐阅读更多精彩内容