FLYSASA

Fair to be late, but never absent


  • 首页

  • 标签

  • 分类

  • 归档

Fair to be late, but never absent

发表于 2018-04-23 | 分类于 Testing

一盏灯, 一片昏黄; 一简书, 一杯淡茶。 守着那一份淡定, 品读属于自己的寂寞。 保持淡定, 才能欣赏到最美丽的风景! 保持淡定, 人生从此不再寂寞。

21AMD&CMD&RequireJS

发表于 2018-03-24 | 分类于 JavaScript

1.为什么要使用模块化?

  • 解决命名冲突 (如多个js文件的命名会重复)
  • 文件依赖管理 (如多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件被加载)
  • 提高代码可读性
  • 代码解耦,提高复用性

2.CMD、AMD、CommonJS 规范分别指什么?有哪些应用

CommonJS:

应用: Node.js等

在网页端没有模块化编程,只是页面的JavaScript逻辑复杂,但也可以工作下去,但在服务器端却一定要有模块,所以虽然JavaScript在web端发展这么多年,第一个流行的模块化规范却由服务器端的JavaScript应用带来,CommonJS规范由NodeJS发扬光大,这标志着JavaScript模块化编程正式登上舞台。

  • 规范内容:
    1 定义模块:根据CommonJS规范,一个单独的文件就是一个模块,每一个模块都是一个单独的作用域,也就是说,在该模块内部定义的变量,无法被其他模块读取,除非定义为global对象的属性
    2 模块输出: 模块只有一个出口,我们把模块希望输出的内容放入module.exports对象
    3 加载模块: 加载模块使用require方法,该方法读取一个文件并执行,返回文件内部的module.exports对象

例:

1
2
var clock = require('clock'); 
clock.start();

这种写法适合服务端,因为在服务器读取模块都是在本地磁盘,加载速度很快,但是如果在客户端,加载模块的时候有可能出现“假死”状况。比如上面的例子中clock的调用必须等待clock.js请求成功,加载完毕。那么,能不能异步加载模块呢?这时就出现了AMD和CMD规范

AMD

应用: RequireJS、curl、Dojo等

英文Asynchronous Module Definition(异步模块定义),是一个在浏览器端模块化开发的规范。由于不是JavaScript原生支持使用AMD规范进行页面开发需要用到对应的库函数,也就是大名鼎鼎RequireJS,实际上AMD 是 RequireJS 在推广过程中对模块定义的规范化的产出。

RequireJS主要解决两个问题:

  • 多个js文件可能有依赖关系,被依赖的文件需要早于依赖它的文件加载到浏览器
  • js加载的时候浏览器会停止页面渲染,加载文件越多,页面失去响应时间越长

在AMD上写一个模块,先定义所有依赖,然后在加载完成后的回调函数中执行.

1
2
3
require(['clock'],function(clock){
clock.start();
});

CMD

应用:SeaJS等

Common Module Definition通用模块定义,CMD规范是国内发展出来的,就像AMD有个RequireJS,CMD有个浏览器的实现SeaJS,SeaJS要解决的问题和RequireJS一样,只不过在模块定义方式和模块解析时机上有所不同。

Sea.js推崇一个文件一个文件,遵循统一的写法,使用Sea.js进行模块化开发可以带来很多好处:

  • 模块的版本管理。通过别名等配置,配合构建工具,可以比较轻松地实现模块的版本管理。
  • 提高可维护性。模块化可以让每个文件的职责单一,非常有利于代码的维护。Sea.js 还提供了 nocache、debug 等插件,拥有在线调试等功能,能比较明显地提升效率
  • 前端性能优化。Sea.js 通过异步加载模块,这对页面性能非常有益。Sea.js 还提供了 combo、flush 等插件,配合服务端,可以很好地对页面性能进行调优。
  • 跨环境共享模块。CMD 模块定义规范与 Node.js 的模块规范非常相近。通过 Sea.js 的 Node.js 版本,可以很方便实现模块的跨服务器和浏览器共享。

在CMD上写一个模块:

1
2
3
4
define(function(require, exports, module) { 
var clock = require('clock');
clock.start();
});

AMD与CMD区别
  • 对依赖的处理不同

    • AMD推崇依赖前置,在定义模块的时候就要声明其依赖的模块
    • CMD推崇就近依赖,只有在用到某个模块的时候再去require
  • 对依赖模块的执行时间处理不同:

    • AMD中模块加载完就执行该模块,所有模块都执行完后会进入require的回调函数,执行主逻辑,结果就是依赖模块的执行顺序和书写顺序不一定一致,看网络速度,谁先下载完谁先执行,但主逻辑一定在所有依赖加载完成后才执行。
    • CMD是先把所有的依赖模块全部加载完后进入主逻辑,遇到require语句的时候才执行对应的模块,结果是模块的执行顺序和书写顺序是完全一致的。

3.使用 requirejs 完善之前的项目,包括如下功能:

  1. 首屏大图为全屏轮播
  2. 有回到顶部功能
  3. 图片区使用瀑布流布局(图片高度不一),下部有加载更多按钮,点击加载更多会加载更多数据(数据在后端 mock)
  4. 使用 r.js 打包应用

    效果预览

    源码地址

20面向对象组件封装

发表于 2018-03-21 | 分类于 JavaScript

1.封装一个轮播组件

实现代码

2.封装一个曝光加载组件

实现代码

3.封装一个Tab组件

实现代码

4.封装一个Modal对话框组件

实现效果

代码

5.封装瀑布流布局组件

实现代码

18对象和原型

发表于 2018-03-18 | 分类于 JavaScript

OOP 指什么?有哪些特性?

1、什么是OO
OO(Object–Oriented )面向对象,OO方法(Object-Oriented Method,面向对象方法,面向对象的方法)是一种把面向对象的思想应用于软件开发过程中,指导开发活动的系统方法,简称OO (Object-Oriented)方法,Object Oriented是建立在“对象”概念基础上的方法学。对象是由数据和容许的操作组成的封装体,与客观实体有直接对应关系,一个对象类定义了具有相似性质的一组对象。而每继承性是对具有层次关系的类的属性和操作进行共享的一种方式。所谓面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统。

2、OOP是什么?
面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)是一种计算机编程架构。OOP 的一条基本原则是计算机程序是由单个能够起到子程序作用的单元或对象组合而成。

核心思想:封装,继承,多态.
OOP 达到了软件工程的三个主要目标:重用性、灵活性和扩展性。为了实现整体运算,每个对象都能够接收信息、处理数据和向其它对象发送信息。
OOP 主要有以下的概念和组件:

组件 - 数据和功能一起在运行着的计算机程序中形成的单元,组件在 OOP 计算机程序中是模块和结构化的基础。
抽象性 - 程序有能力忽略正在处理中信息的某些方面,即对信息主要方面关注的能力。
封装 - 也叫做信息封装:确保组件不会以不可预期的方式改变其它组件的内部状态;只有在那些提供了内部状态改变方法的组件中,才可以访问其内部状态。每类组件都提供了一个与其它组件联系的接口,并规定了其它组件进行调用的方法。
多态性 - 组件的引用和类集会涉及到其它许多不同类型的组件,而且引用组件所产生的结果得依据实际调用的类型。
继承性 - 允许在现存的组件基础上创建子类组件,这统一并增强了多态性和封装性。典型地来说就是用类来对组件进行分组,而且还可以定义新类为现存的类的扩展,这样就可以将类组织成树形或网状结构,这体现了动作的通用性。
由于抽象性、封装性、重用性以及便于使用等方面的原因,以组件为基础的编程在脚本语言中已经变得特别流行。Python 和 Ruby 是最近才出现的语言,在开发时完全采用了 OOP 的思想,而流行的 Perl 脚本语言从版本5开始也慢慢地加入了新的面向对象的功能组件。用组件代替“现实”上的实体成为 JavaScript(ECMAScript) 得以流行的原因,有论证表明对组件进行适当的组合就可以在英特网上代替 HTML 和 XML 的文档对象模型(DOM)。

如何通过构造函数的方式创建一个拥有属性和方法的对象?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 第一种方法
function Person(name, age) {
this.name = name;
this.age = age;
this.sayName = function() {
console.log(this.name);
}
}
var p1 = new Person('Byron', 25);
// 第二种方法
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
console.log(this.name);
}

var p1 = new Person('Byron', 25);
p1.sayName();

prototype 是什么?有什么特性?

1.是什么

  • 显式原型 explicit prototype property:每一个函数在创建之后都会拥有一个名为prototype的属性,这个属性指向函数的原型对象。Note:通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性。
  • 隐式原型 implicit prototype link:JavaScript中任意对象都有一个内置属性[[prototype]],在ES5之前没有标准的方法访问这个内置属性,但是大多数浏览器都支持通过__proto__来访问。ES5中有了对于这个内置属性标准的Get方法Object.getPrototypeOf(). Note: Object.prototype 这个对象是个例外,它的__proto__值为null.
  • 二者的关系:
    隐式原型指向创建这个对象的函数(constructor)的prototype

2.作用是什么?

  • 显式原型的作用:用来实现基于原型的继承与属性的共享。
  • 隐式原型的作用:构成原型链,同样用于实现基于原型的继承。举个例子,当我们访问obj这个对象中的x属性时,如果在obj中找不到,那么就会沿着__proto__依次查找。

3.__proto__的指向
__proto__的指向到底如何判断呢?根据ECMA定义 ‘to the value of its constructor’s “prototype” ‘ —-指向创建这个对象的函数的显式原型。所以关键的点在于找到创建这个对象的构造函数,接下来就来看一下JS中对象被创建的方式,有三种方式:(1)对象字面量的方式 (2)new 的方式 (3)ES5中的Object.create() 但是我认为本质上只有一种方式,也就是通过new来创建。为什么这么说呢,首先字面量的方式是一种为了开发人员更方便创建对象的一个语法糖,本质就是 var o = new Object(); o.xx = xx;o.yy=yy; 再来看看Object.create(),这是ES5中新增的方法,在这之前这被称为原型式继承。

画出如下代码的原型图

1
2
3
4
5
6
7
8
9
10
11
12
13
function People (name){
this.name = name;
this.sayName = function(){
console.log('my name is:' + this.name);
}
}

People.prototype.walk = function(){
console.log(this.name + ' is walking');
}

var p1 = new People('饥人谷');
var p2 = new People('前端');

原型图.jpg

创建一个 Car 对象,拥有属性name、color、status;拥有方法run,stop,getStatus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
function Car (name,color,status){
this.name = name
this.color = color
this.status = status
}
Car.prototype = {
run: function(){
if(this.status == 1){
console.log('is running')
}
},
stop: function(){
if(this.status == 0){
console.log('is stoped')
}
},
getStatus: function(){
console.log('this.status')
},
}

var car1 = new Car('benz','red','1')

创建一个 GoTop 对象,当 new 一个 GotTop 对象则会在页面上创建一个回到顶部的元素,点击页面滚动到顶部。拥有以下属性和方法

  1. ct属性,GoTop 对应的 DOM 元素的容器
  2. target属性, GoTop 对应的 DOM 元素
  3. bindEvent 方法, 用于绑定事件
  4. createNode 方法, 用于在容器内创建节点
    代码实现
    效果预览

使用木桶布局实现一个图片墙

代码实现
效果预览

19对象和原型

发表于 2018-03-18 | 分类于 JavaScript

1.apply、call 、bind有什么作用,什么区别?

apply和call

apply和call都是为了改变某个函数运行时的上下文而存在的(就是为了改变函数内部this的指向);

如果使用apply或call方法,那么this指向他们的第一个参数,apply的第二个参数是一个参数数组,call的第二个及其以后的参数都是数组里的元素,需要全部列举出来。apply 和 call 的用法几乎相同, 唯一的差别在于参数传递方式不一样。 apply粗鲁些直接一个数组怼过来,而call则细腻些将数组里的元素一个一个传递进来

function(){console.log(this.a)}.call(undefined)

如果你传的 context 是 null 或者 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

他们常用用法:

  • 求数组中的最大和最小值
    利用他们扩充作用域 从而借助Math来使用min和max的方法
    注:由于没有对象调用这个方法,所以第一个参数可以写作null或者Math本身
    1
    2
    3
    var arr = [10,20,30,40,50]
    var max = Math.max.apply(null,arr)
    var min = Math.min.call(Math,10,20,30,40,50)

(ps:这样看起来apply和call更像是寄生虫,让它的参数 能够使用本不属于它的技能=.=)

  • 数组之间的追加
    1
    2
    3
    4
    5
    var arr1 = [1,2,3]
    var arr2 = [4,5,6]
    var total = [].push.apply(arr1,arr2) //返回长度6因为this是arr1,所以追加到arr1上
    //arr1 [1,2,3,4,5,6]
    //arr2 [4,5,6]

image.png

  • 验证是否是数组(前提toString()方法没有被重写)
    1
    2
    3
    4
    5
    function isArray(obj){
    return Object.prototype.toString.call(obj) == '[object Array]'
    }
    isArray([]) //true
    isArray('haha') //false
  • 将类数组转化为数组
    1
    var trueArr = Array.prototype.slice.call(arrayLike)
  • 利用call和apply做继承
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    function Person(name,age){
    this.name = name
    this.age = age
    this.sayAge = function(){
    console.log(this.age)
    }
    }
    function Male(){
    Person.call(this,name,age) //在子类构造函数中执行父类的构造函数
    }
    var haha = new Male('haha',5)
  • ######使用log代理console.log

    1
    2
    3
    4
    function log(){
    console.log.apply(console,arguments)
    }
    // 当然也有更方便的 var log = console.log()

关于bind()

也是改变函数体内this的指向

bind会创建一个新函数,称为绑定函数,当调用这个函数的时候,绑定函数会以创建它时传入bind()方法时的第一个参数作为this,传入bind()方法的第二个及以后的参数加上绑定函数运行时本身的参数按照顺序作为原函数的参数来调用原函数

  • 参数的使用:
    call 是把第二个及以后的参数作为 fn 方法的实参传进去,而 fn1 方法的实参实则是在 bind 中参数的基础上再往后排。在下面的例子中,bind方法有参数’haha’,然后加上fn1传递的参数’A’, ‘B’, ‘C’,一起作为fn的参数顺序执行.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    function fn(a, b, c) {
    console.log(a, b, c);
    }
    var fn1 = fn.bind(null, 'haha');

    fn('A', 'B', 'C'); // A B C
    fn1('A', 'B', 'C'); // haha A B
    fn1('B', 'C'); // haha B C
    fn.call(null, 'haha'); // haha undefined undefined

image.png

bind与apply、call最大的区别就是:bind不会立即调用,其他两个会立即调用,bind返回值是一个改变了上下文 this 后的函数.

综上:
三个使用的异同点
1.都是用来改变函数的this对象的指向的
2.第一个参数就是this要指向的对象
3.都可以利用后续参数传参
4.bind返回一个新函数,便于稍后调用,apply和call是立即调用


原型链相关问题

this是什么?

随着函数使用场合的不同,this的值会发生变化。但是有一个总的原则,那就是this指的是调用this所在函数的那个对象

2.以下代码输出什么?

1
2
3
4
5
6
7
8
var john = { 
firstName: "John"
}
function func() {
alert(this.firstName + ": hi!")
}
john.sayHi = func
john.sayHi()

输出: John: hi!
解析:函数作为对象方法调用,会使得 this 的值成为对象本身。john调用的这个函数,所以这里的this指代john对象.

3.下面代码输出什么,为什么

1
2
3
4
func() 
function func() {
alert(this)
}

输出: window对象
解析: 在函数被直接调用时this绑定到全局对象。在浏览器中,window 就是该全局对象

4.下面代码输出什么,为什么

1
2
3
4
5
6
document.addEventListener('click', function(e){
console.log(this);
setTimeout(function(){
console.log(this);
}, 200);
}, false);

输出:依次document window对象
解析:在事件处理程序中this代表事件源DOM对象,所以第一个为document,
setTimeout内的函数属于回调函数,理解为f1.call(null,f2),所以this指向window

5.下面代码输出什么,为什么

1
2
3
4
5
6
7
8
var john = { 
firstName: "John"
}

function func() {
alert( this.firstName )
}
func.call(john)

输出:John
解析: call中传入的第一个参数即this的指向

6.以下代码有什么问题,如何修改

1
2
3
4
5
6
7
8
9
10
11
12
var module= {
bind: function(){
$btn.on('click', function(){
console.log(this) //this指向$btn
this.showMsg();
})
},

showMsg: function(){
console.log('饥人谷');
}
}

修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
var module= {
bind: function(){
var _this = this
$btn.on('click', function(){
console.log(_this) //this指向module
_this.showMsg();
})
},

showMsg: function(){
console.log('饥人谷');
}
}

7.有如下代码,解释Person、 prototype、_proto__、p、constructor之间的关联。

1
2
3
4
5
6
7
8
function Person(name){
this.name = name;
}
Person.prototype.sayName = function(){
console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();

关系:

1
2
Person.prototype.constructor === Person
p.__pro__ === Person.prototype

原型图 .png

8.上例中,对象 p可以这样调用 p.toString()。toString是哪里来的? 画出原型图?并解释什么是原型链。

原型图2.png

  • 解析: p是Person构造函数的实例,p首先会从自身上找有没有toString()方法,没有的话会沿着__proto__属性找到Person.prototype对象,在这个对象上继续找有没有这个方法,如果还是没有会继续沿着Person.prototype.__proto__属性逐级往上找,直到Object.prototype为止,如果还是没有该方法,则返回null,期间找到了就调用该方法.
    p最后沿着原型链在Object.prototype中找到了toString()方法,所以就可以调用该方法,这也叫做继承方法.
  • 原型链:
    每个构造函数都有一个原型对象,原型对象都包含指向其构造函数的指针constructor,而实例都包含一个指向这个原型对象的__proto__指针。如果我们让这个原型对象等于另一个类的实例,则此时这个原型对象也将包含一个指向另一个原型对象的指针__proto__,以此为依据,层层递进,就构成了实例与原型的链条,成为原型链。
  • 原型链作用
    在访问对象的属性方法时,如果在对象本身中没有找到,则会去沿着原型链逐级向上查找,期间找到则返回该属性方法,如果这个原型链都无法找到该属性方法,则返回undefined。原型链一般实现为一个链表,这样就可以按照一定的顺序来查找,原型链是实现继承的主要方法。

注意:

当new一个类的时候,经历的步骤:

1.创建类的实例,把一个空的对象的__proto__属性设置为F.prototype(F为该类)
2.初始化实例,函数F被传入参数并调用,关键this被设定为该实例
3.返回实例对象

归纳:

1.我们通过构造函数定义了类,类自动获得属性prototype
2.每个类的实例都会有一个内部属性__proto__,指向类的prototype原型
3.一切函数都是由Function类创建的,所以Function.prototype === 被创建的函数.__proto__
4.一切函数的原型对象都是由 Object 类创建的,所以Object.prototype === 一切函数.prototype.__proto__
image.png

9.问题: 对String做扩展,实现如下方式获取字符串中频率最高的字符

1
2
3
var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch); //d , 因为d 出现了5次

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
String.prototype.getMostOften = function(){
var obj = {}
for(var i=0;i<this.length;i++){
var item = this.substr(i,1) //substr(start,length) 截取字符串,start截取开始位置,length截取长度
//此时item分别等于a h b b c c d e d d d d f g
if(!obj[item]){
obj[item] = 1 //如果obj对象中没有item属性,则设置item: 1;
}else{
obj[item]++ //如果有该属性item属性对应的值加1
}
}
var num = 0,max = null
for(key in obj){ //遍历obj中的属性
console.log(key) //a h b c d e f g
if(obj[key] > num){ //即某个属性对应的值大于num
num = obj[key] //最大值
max = key //最大值的属性
}
}
return max
}

var str = 'ahbbccdeddddfg';
var ch = str.getMostOften();
console.log(ch);

10.问题: instanceOf有什么作用?内部逻辑是如何实现的?

  • 作用:判断一个对象是否是某个类的实例,是的话返回true,不是的话返回false
    举例:

    1
    2
    [1,2,3] instanceof Array //true
    [1,2,3] instanceof Object //true
  • 实现:a instanceof b的判断规则是:沿着a的__proto__这条线来找,同时沿着b的prototype这条线来找,如果两条线逐级向上查找能找到同一个引用,返回true,证明A是B类型的实例,否则返回false。代码如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    function InstanceOf(a,b){
    var proto=a.__proto__;
    do{
    if(proto === b.prototype){
    return true;
    }else{
    proto=proto.__proto__;
    }
    }
    while(proto)
    return false;
    }

继承相关问题

11.问题: 继承有什么作用?

继承是指一个对象直接使用另一对象的属性和方法。通过继承,可以使子类共享父类的属性和方法,可以覆盖(重写)和扩展父类的属性和方法,减少内存的使用,提高代码复用性。

12.问题: 下面两种写法有什么区别?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//方法1
function People(name, sex){
this.name = name;
this.sex = sex;
this.printName = function(){
console.log(this.name);
}
}
var p1 = new People('饥人谷', 2)

//方法2
function Person(name, sex){
this.name = name;
this.sex = sex;
}

Person.prototype.printName = function(){
console.log(this.name);
}
var p1 = new Person('若愚', 27);
  • 方法1是将printName()作为构造函数的方法,在实例化的时候,每次都要创建printName(),作为新对象的私有属性,这样每个实例都要重复一遍,会浪费内存
  • 方法2是将printName()作为构造函数原型上的方法,在实例化的时候,p1可以调用,其它的实例也可以来调用,是作为共享的方法,可以优化内存空间

13.问题: Object.create 有什么作用?兼容性如何?

  • 作用:
    Object.create() 方法创建一个拥有指定原型和若干指定属性的对象
    Object.create()接收两个参数,作用是创建接收到的第一个参数的副本,第二个参数是可选的、额外传入副本里的属性,以第二个参数指定的任何属性都会传入副本中并覆盖已有的同名属性,但原型对象上的同名属性不会被改变。
    如例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    var person = {
    name: 'tom',
    friends: ['a', 'b', 'c']
    }

    var anotherPerson = Object.create(person, { //将anotherPerson中的__proto__替换成person
    name: { //第二个参数是额外传入的属性,会覆盖之前的同名属性
    value: 'tony'
    }
    })

    console.log(anotherPerson.name) //tony
    console.log(person.name) //tom
  • 兼容性:各大浏览器的最新版本(包括IE9)都部署了这个方法
    解决低版本iE浏览器问题:

    1
    2
    3
    4
    5
    6
    7
    if(!Object.create){
    Object.create = function(obj){
    function fn(){}
    fn.prototype = obj //prototype即方法 fn继承了obj.prototype的方法
    return new fn()
    }
    }

14.问题: hasOwnProperty有什么作用? 如何使用?

  • 作用: 判断属性和方法时自己的还是父类的,可以用hasOwnProperty,可以判断是对象自定义属性而不是原型链上的属性,返回布尔值
    hasOwnProperty是javascript中唯一一个处理属性但是不查找原型链的函数
  • 使用: 实例.hasOwnProperty('属性名'),返回true则属性存在于实例中,false则属性存在于原型中。
    1
    2
    3
    4
    5
    6
    var a = {
    name: 'a'
    };
    a.hasOwnProperty('name');//true
    a.hasOwnProperty('toString');//false
    a.hasOwnProperty('valueOf');//false

15.问题如下代码中call的作用是什么?

1
2
3
4
5
6
7
8
function Person(name, sex){
this.name = name;
this.sex = sex;
}
function Male(name, sex, age){
Person.call(this, name, sex); //这里的 call 有什么作用
this.age = age;
}
  • 作用: 绑定this指向,属性获取
    Male对象属性的获取是通过构造函数Person在其内部的执行,我们在一个类中执行另外一个类的构造函数,就可以把属性复制到自己内部,但是我们需要把环境改到自己的作用域内,就需要借助call,将this指向Male类的实例. 这样在执行Person.call(this, name, sex)会赋予实例这些属性.

16.问题: 补全代码,实现继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function Person(name, sex){
this.name = name
this.sex = sex
}

Person.prototype.getName = function(){
console.log('My name is' + this.name)
};

function Male(name, sex, age){
Person.call(this,name,sex) //获取父类Person的属性,Person构造函数中的this指向实例,传入的参数this也指向实例
this.age = age //添加age属性
}

Male.prototype = Object.create(Person.prototype) //获取父类的方法
Male.prototype.constructor = Male //将constructor有person类重新绑定到Male类

Male.prototype.getAge = function(){
console.log('My age is' + this.age)
};

var ruoyu = new Male('haha', '男', 27);
ruoyu.getName();

总结:

1.获取父类属性
方法: 在子类的构造函数中,执行父类的构造函数,借助call绑定this指向实例

1
2
3
function 子类(){
父类.call(this,arguments) //this指向子类的实例,执行一遍后获取到父类的属性
}

2.获取父类的方法
方法一般都设置在类的prototype中,所以从这点出发
实现: 借助Object.create()方法,将子类.prototype.__proto__ = 父类.prototype

1
2
子类.prototype = Object.create(父类.prototype)   //设置完后,此时 子类.prototype.constructor为父类,需纠正
子类.prototype.constructor = 子类

17瀑布流布局

发表于 2018-01-06 | 分类于 JavaScript

题目1: 实现一个瀑布流布局效果

  • 代码实现

题目2 : 实现一个新闻瀑布流新闻网站,查看效果
jsonp 接口参数: http://platform.sina.com.cn/slide/album_tech?jsoncallback=func&app_key=1271687855&num=3&page=4

  • 代码实现

16 轮播图

发表于 2018-01-05 | 分类于 JavaScript

题目1: 轮播的实现原理是怎样的?如果让你来实现,你会抽象出哪些函数(or接口)供使用?(比如 play())

  • 实现原理,左右滚动轮播为例

    • 关于布局:
      1. 初步布局:首先父容器相对定位,设定好宽高(确定轮播框大小),设置`overflow:hidden`溢出隐藏,在父容器内部设置`img`容器绝对定位,方便确定位置(注意不要限制死容器宽高,因为如果后面加入新的图片得修改值),设置`overflow:hidden`形成BFC,防止因浮动产生高度坍塌
      2.`img`父容器内部为多个包含a链接(方便跳转链接)和img的li元素,给img设置好宽高,li元素左浮,横向排成一排,左右轮播键和底部的圆点都可通过绝对定位确定位置.
      
    • 关于实现逻辑:
      1.通过移动img容器的位置来展现不同的图片,达到切换效果.实现方法:在img容器中,clone最后一个元素至首部,clone第一个元素至尾部,通过计算
      (imgCount+2) * imgWidth得到img容器的宽度,imgCount为初始li元素的个数.
      先确定好第一张展示图片的位置为$imgCt.css({left: -imgWidth}),当图片左右切换,img容器位置左右加减.当运动到clone首图片时,立即跳转到原来的首图片,设置css属性$imgCt.css({left: -imgWidth}).当运动到clone尾图片时,立即跳转到原来的尾图片$imgCt.css({left: -imgCount*imgWidth}),从而达到无限左右滚动效果,css属性切换在人眼看来是连贯的.
      2.另外需要在展示不同图片的时候,知道这是第几张,设置标记位,第一张标记位为0,后面累加.最后一张为imgCount-1,通过不同的标记位img容器移动对应的位置,实现跳转图片.
  • 函数接口:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    //自动循环播放
    autoPlay()

    //左右切换键
    playNext() //切换至下一张
    playPre() //切换至上一张

    //底部导航按钮切换效果
    setBullet()

题目2: 实现视频中的左右滚动无限循环轮播效果

实现方法1
实现方法2

题目3: 实现一个渐变轮播效果, 效果范例

实现代码

15 懒加载

发表于 2018-01-04 | 分类于 JavaScript

题目1:如何判断一个元素是否出现在窗口可视范围(浏览器的上边缘和下边缘之间,肉眼可视)。写一个函数 isVisible实现

1
2
3
4
5
6
7
8
9
10
function isVisible($node){
var scrollTop = $(window).scrollTop() //窗口滚动距离
var windowHeight = $(window).height() //窗口的高度
var offsetTop = $node.offset().top //目标元素相对于页面顶部的偏移距离
//两个临界点,最小值是滚动高度,最大值是窗口高度加窗口滚动的距离
if(offsetTop < scrollTop + windowHeight && offsetTop > scrollTop){
return true
}
return false
}

题目2:当窗口滚动时,判断一个元素是不是出现在窗口可视范围。每次出现都在控制台打印 true 。用代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$(window).on('scroll',function(){
if(isVisible($node){
console.log(true)
}
function isVisible($node){
var scrollTop = $(window).scrollTop() //窗口滚动距离
var windowHeight = $(window).height() //窗口的高度
var offsetTop = $node.offset().top //目标元素相对于页面顶部的偏移距离
//两个临界点,最小值是滚动高度,最大值是窗口高度加窗口滚动的距离
if(offsetTop < scrollTop + windowHeight && offsetTop > scrollTop){
console.log('true')
return true
}
return false
}
})

题目3:当窗口滚动时,判断一个元素是不是出现在窗口可视范围。在元素第一次出现时在控制台打印 true,以后再次出现不做任何处理。用代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
$(window).on('scroll',function(){
$('.container img').each(function(){
if( isVisible($(this)) && !isLoaded($(this)) ){
//遍历每个图片如果出现在可视范围内并且没有被加载过,加载图片并且打印true,否则不做处理
loadImg($(this))
console.log("true")
}
})
})

function isVisible($img){ //检查元素是否出现在窗口可视范围
var scrollTop = $(window).scrollTop() //滚动高度
var windowHeight = $(window).height() //窗口高度
var offsetTop = $img.offset().top //页面顶点至目标的高度
if(offsetTop < scrollTop + windowHeight && offsetTop > scrollTop) //两个临界点,一个最小值是滚动高度,一个最大值是滚动高度加窗口高度
{
return true
}
return false
}

function isLoaded($img){ //返回布尔值
return $img.attr('data-src') === $img.attr('src')
}

function loadImg(#img) {
$img.attr('src',$img.attr('data-src'))
}

题目4: 图片懒加载的原理是什么?

  • 为什么要懒加载:
    懒加载即延迟,对于图片过多的页面,为了加快页面加载速度,我们需要将页面内未出现在可视区域内的图片先不做加载, 等到滚动到可视区域后再去加载。
    这样一来页面加载性能大幅提升,提高了用户体验。
  • 实现原理:
    • 在页面载入时将img标签內的src指向一个小图片,即占位图,将真实地址存放于一个自定义属性data-src中,然后获取页面上的img标签并保存,开启一个定时器来遍历保存的img标签,接下来判断每个img是否出现在可视区,当某个img出现在了可视区域,就将真实地址赋值给该img的src并将该img从数组中删除以避免重复判断。
    • 判断元素是否出现在了可视区
    • 实现流程:
      1.网页滚动事件触发
      2.执行加载图片操作
      3.判断图片是否在可视区且是否已经加载过
      4.在可视区且未被加载过则动态地将data-src的值赋给该图片的src属性。

题目5: 实现视频中的图片懒加载效果

实现:http://js.jirengu.com/jebafozuwa/1/edit

14 jQuery与jQuery ajax

发表于 2018-01-03 | 分类于 JavaScript

题目1: jQuery 中, $(document).ready()是什么意思?

定义和用法:

当 DOM(文档对象模型) 已经加载,并且页面(包括图像)已经完全呈现时,会发生 ready 事件。
由于该事件在文档就绪后发生,因此把所有其他的 jQuery 事件和函数置于该事件中是非常好的做法。
ready() 函数规定当 ready 事件发生时执行的代码。
ready() 函数仅能用于当前文档,因此无需选择器。

允许使用以下三种语法:
$(document).ready(function)
$().ready(function)
$(function)

jQuery中$(document).ready与Javascript中window.onload区别:

window.onload:
window.onload在页面的DOM加载完成,所有的图片、子frame等所有的元素都加载完成的时候才会触发。
$(document).ready():
$(document).ready方法发生在DOM树构造完成,而不会等到其余的所有的元素都加载完成。其实说白了就是ready方法在onload之前发生,一般发生在DOM树构造完成的时候。

具体一些,可以从以下几方面对比$(document).ready和window.onload的区别:

1.执行时间
window.onload必须等到页面内包括图片的所有元素加载完毕后才能执行。
$(document).ready是DOM结构绘制完毕后就执行,不必等到图片等资源加载完成后才执行。

2.编写个数不同
window.onload不能同时编写多个,如果有多个window.onload方法,后面会覆盖前面,并且只会执行一个onload方法。
$(document).ready可以同时编写多个,并且都可以得到执行。
如下例:

1
2
3
4
5
6
7
8
9
10
11
12
window.onload = function(){
console.log("window.onload event1");
}
window.onload = function(){
console.log("window.onload event2");
}
$(document).ready(function(){
console.log("jquery ready event1");
})
$(document).ready(function(){
console.log("jquery ready event2");
})

执行结果如下:
输出结果
可以看出ready先于onload事件。并且onload只能有一个,后面覆盖前面,而ready恰好相反。

3.简化写法
window.onload没有简化写法。
$(document).ready(function(){})可以简写成$(function(){});
在一些开发中,大多数时候,第一行写的是:

1
2
3
$(document).ready(function(){
//coding...
});

关于$(window).load:

$(window).load与window.onload其实没什么大的区别
jquery API中提到$(window).load方法是$(window).on('load',handler)的shortcut,而且$(window).on('load',handler)相当于window.onload方法

1
2
3
4
5
6
7
$(window).load(function (){  
// coding
});
//等价于 JavaScript 中的以下代码
window.onload = function (){
// coding
}

如果真要说区别的
$(window).load(handler)可以用多次使用,并且handler都会依次执行。但是window.onload就不行,就像上面介绍的一样,window.onload = handler后面的hanlder会覆盖之前的handler。

注意:由于在$(document).ready()方法内注册的事件,只要 DOM 就绪就会被执行,因此可能此时元素的关联文件未下载完。例如与图片有关的 html 下载完毕,并且已经解析为 DOM 树了,但很有可能图片还没有加载完毕,所以获取图片的高度和宽度这样的属性此时不一定有效。要解决这个问题,可以使用 jquery 中另一个关于页面加载的方法 —load() 方法。 Load() 方法会在元素的 onload 事件中绑定一个处理函数。如果处理函数绑定给 window 对象,则会在所有内容 ( 包括窗口、框架、对象和图像等 ) 加载完毕后触发,如果处理函数绑定在元素上,则会在元素的内容加载完毕后触发。

用原生JS实现jQuery的ready方法

那么,对于某些特殊需求,不希望使用jQuery,但又想实现jQuery的ready方法。该如何用原生JS实现jQuery的ready方法呢?下面是其中之一的做法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function ready(fn){  
if(document.addEventListener){
//标准浏览器
document.addEventListener('DOMContentLoaded',function(){
//注销事件,避免反复触发
document.removeEventListener('DOMContentLoaded',arguments.callee,false);
//执行函数
fn();
},false);
}else if(document.attachEvent){
//IE浏览器
document.attachEvent('onreadystatechange',function(){
if(document.readyState=='complete'){
document.detachEvent('onreadystatechange',arguments.callee);
//执行函数
fn();
}
});
}
}

下面用一段代码验证ready函数的正确性:

1
2
3
4
5
6
window.onload = function(){
console.log("window.onload event");
}
ready(function(){
console.log('window ready event')
})

执行效果如下:
执行效果

题目2: $node.html()和$node.text()的区别?

  • 相同点:
    html()和text()都是读写两用方法。

  • 区别:

    • html()对jQuery对象的html进行操作,相当于原生js的innerHTML;text()对jQuery对象的text进行操作,相当于原生js的innerText
    • 没有传递参数时,html()获取的是第一个匹配元素的innerHTML;text()获取的是所有匹配元素的innerText
    • 传递了string参数时,html()修改所有匹配元素的innerHTML为参数值,text()修改所有匹配元素的innerText为参数值
      如例:
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      <body>
      <ul>
      <li><span>item1 </span></li>
      <li><span>item2 </span></li>
      <li><span>item3 </span></li>

      </ul>
      <script>
      console.log($('li').html())//<span>item1 </span>
      console.log($('li').text())//item1 item2 item3

      console.log($('li').html('<span>insert span</span>'))//
      console.log($('li').text('insert text'))//
      </script>
      </body>

下面代码打印结果:

1
2
console.log($('li').html())//<span>item1 </span>
console.log($('li').text())//item1 item2 item3

下面代码打印结果:

1
2
console.log($('li').html('<span>insert span</span>'))
console.log($('li').text('insert text'))

题目3: $.extend 的作用和用法?

定义
jQuery.extend() 函数用于将一个或多个对象的内容合并到目标对象。相同属性后面对象的值覆盖前面对象的值,target将被修改并通过$.extend()返回。参数 deep 为布尔值true/false,用来设置合并操作是否递归(深拷贝)。$.extend( [deep ], target, object1 [, objectN ] )
注意:

  1. 如果只为$.extend()指定了一个参数,则意味着参数target被省略。此时,target就是jQuery对象本身。通过这种方式,我们可以为全局对象jQuery添加新的函数。
  2. 如果多个对象具有相同的属性,则后者会覆盖前者的属性值。

用法:
如果我们想保留原对象,可通过传递一个空对象作为目标对象:
var object = $.extend({}, object1, object2); //将object1, object2合并到{}中
默认$.extend()合并操作是浅复制,如果第一个对象的属性本身是一个对象或数组,那么它将完全用第二个对象相同的key重写一个属性。这些值不会被合并。如果将 true作为该函数的第一个参数,那么会在对象上进行递归的合并。

######语法:
$.extend( target [, object1 ] [, objectN ] )

如例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
var object1 = {
amy: 0,
tom: {
height: 180, user: {
age: 20
}
},
}
var object2 = {
jim: 100,
tom: {
weight: 100, user: {
age: 100
}
}
}
console.log($.extend(object1, object2))//浅复制,将object2合并到object1中
console.log(object1)//object1为返回的最终结果
console.log(object2)//object2值不变
console.log($.extend(true, object1, object2))//深复制,将object2合并到object1中
</script>

打印结果:

1
2
console.log($.extend(object1, object2))
//浅复制,将object2合并到object1中,tom对象属性完全被object2中的tom属性取代


1
console.log(object1)//object1为返回合并后的最终结果


1
console.log(object2)//object2值不变


1
2
console.log($.extend(true, object1, object2))
//深复制,将object2合并到object1中


关于深复制和浅复制的区别参考:https://www.cnblogs.com/tracylin/p/5346314.html

题目4: jQuery 的链式调用是什么?

链式调用适用于异步编程,可避免线程阻塞,实现原理是在当前函数执行完后return this,即返回该函数的执行环境,下一个函数就可以继续在这个函数下运行了,结果就是多种方法在一个jQuery对象上一个接一个地调用
示例:

1
2
3
4
5
6
7
8
9
10
11
<body>
<p>hello world</p>
<h2>bybe world</h2>
<script>
$('p').on('mouseenter', function () {
$(this).css('background-color', 'red')
}).on('mouseleave', function () {
$(this).css('background-color', 'blue')
}).parents('body').find('h2').toggle(500)
</script>
</body>

执行效果:
初始状态

500ms后bybe world消失

鼠标放置上去
鼠标移开
本例中,mouseenter和mouseleave是事件监听,只有事件触发后才会执行相应函数中的代码,属于异步执行,与以上所说的在同一jQuery上一个接一个地调用方法并不冲突。
结果就是无论如何js引擎都会先执行$('p').parents('body').find('h2').toggle(500)切换h2的显示状态为隐藏,再根据用户是否触发鼠标事件来计算结果。

题目5: jQuery 中 data 函数的作用?

  • #####jquery data()的作用
    data() 方法向被选元素附加数据,或者从被选元素获取数据。
    通过data()函数存取的数据都是临时数据,一旦页面刷新,之前存放的数据都将不复存在。
    该函数属于jQuery对象(实例)。如果需要移除通过data()函数存放的数据,请使用 removeData() 函数。

  • #####jquery data的使用方式
    1、获取附加的data的值
    $(selector).data(name)
    参数说明
    name:可选。规定要取回的数据的名称。
    如果没有规定名称,则该方法将以对象的形式从元素中返回所有存储的数据。

2、用name和value为对象附加数据
$(selector).data(name,value)
参数说明
selector:为需要附加或者获取数据的对象。
name:参数为数据的名称。
value:参数为数据的值。

3、使用对象向元素附加数据
使用带有名称/值对的对象向被选元素添加数据。
除了以提供 name 和 value 的方式进行赋值,我们还可以直接传入另一个对象( “another” )作为参数。这种情况下,“another” 的属性名称和属性值将被视为多个键值对,从中提取的 “name” 和 “value” 都会被复制到目标对象的缓存中。
$(selector).data(object)
参数说明
object:必需。规定包含名称/值对的对象。

示例:

1
2
3
4
5
6
7
$('body').data('name', 'haha')
$('body').data('hobby', { fav: 'music', love: 'chicken' })
$('body').data({ arr: [1, 2, 3, 4, 5] })

console.log($('body').data('name'))//haha
console.log($('body').data())
//{ name: "haha",hooby: { fav: "music", love: "chicken" },arr: [1,2,3,4,5] }

打印结果:
image.png

题目6:写出以下功能对应的 jQuery 方法:

  • 给元素 $node 添加 class active,给元素 $noed 删除 class active

    1
    2
    $node.addClass('active')
    $node.removeClass('active')
  • 展示元素$node, 隐藏元素$node

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //方法1:
    $node.show()
    $node.hide()
    //方法2:
    $node.css('display','block')
    $node.css('display','none')
    //方法3:
    //给node设置css属性{display: none;},默认隐藏; 增加active属性 node.active{display: block;}显示
    $node.addClass('active'); //显示
    $node.removeClass('active'); //隐藏
  • 获取元素$node 的 属性: id、src、title, 修改以上属性

    1
    2
    3
    4
    5
    6
    7
    8
    //获取属性
    $node.attr('id')
    $node.attr('src')
    $node.attr('title')
    //修改属性
    $node.attr('id','newId')
    $node.attr('src','newSrc')
    $node.attr('title','newTitle')
  • 给$node 添加自定义属性data-src

    1
    $node.prop('data-src')
  • 在$ct 内部最开头添加元素$node

    1
    2
    3
    $ct.prepend($node)
    //或
    $node.prependTo($ct)
  • 在$ct 内部最末尾添加元素$node

    1
    2
    3
    $ct.append($node)
    //或者
    $node.appenTo($ct)
  • 删除$node

    1
    2
    $node.remove()
    $ct.detach($node)
  • 把$ct里内容清空

    1
    2
    $ct.empty()
    $ct.text('')
  • 在$ct 里设置 html<div class="btn"></div>

    1
    $ct.html('<div class="btn"></div>')
  • 获取、设置$node 的宽度、高度(分别不包括内边距、包括内边距、包括边框、包括外边距)

获取宽高:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//不包括内边距
$node.width()
$node.height()
$node.css('width')
$node.css('height')

//包括内边距
$node.innerWight()
$node.innerHeight()

//包括内边距,包括边框
$node.outerWidth() //不传参数或参数为false
$node.outerHeight() //不传参数或参数为false

//包括内边距,边框,外边距
$node.outerWidth(true)
$node.outerHeight(true)

设置宽高:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//不包括内边距
$node.width(100) //如果没有规定长度单位,则使用默认的 px 单位
$node.height(100)
$node.css({width:'200px',height:'300px'})//设置元素的宽度和高度,也可以不要引号和单位

//包括内边距
$node.innerWidth(30)
$node.innerHeight(30)

//包括内边距,包括边框
$node.outerWidth(60)
$node.outerHeight(30)

//包括内边距,包括边框,包括外边距
$node.outerWidth(70,true)
$node.outerHeight(70,true)

  • 获取窗口滚动条垂直滚动距离

    1
    $(window).scrollTop()
  • 获取$node 到根节点水平、垂直偏移距离

    1
    2
    $node.offset().left
    $node.offset().top
  • 修改$node 的样式,字体颜色设置红色,字体大小设置14px

    1
    2
    3
    4
    $node.css({
    'color': 'red',
    'font-size': '14px'
    })
  • 遍历节点,把每个节点里面的文本内容重复一遍

    1
    2
    3
    $node.each(function(){
    $(this).text($(this).text() + $(this).text())
    })
  • 从$ct 里查找 class 为 .item的子元素

    1
    2
    $ct.find('.item')
    $ct.children('.item')
  • 获取$ct 里面的所有孩子

    1
    $ct.children()
  • 对于$node,向上找到 class 为’.ct’的父亲,再从该父亲找到’.panel’的孩子

    1
    $node.parents('.ct').find('.panel')
  • 获取选择元素的数量

    1
    $node.length
  • 获取当前元素在兄弟中的排行

    1
    node.index()

题目7:

  • 用jQuery实现以下操作
    • 当点击$btn 时,让 $btn 的背景色变为红色再变为蓝色
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      <body>
      <button class="btn">按钮</button>
      <script>
      var $btn = $('.btn')
      $btn.on('click',function(){
      $btn.css({
      'background': 'red'
      })
      setTimeout(function(){
      $btn.css({'background': 'blue'})
      },500)
      })
      </script>
      </body>

效果预览:http://js.jirengu.com/maqihelosa/1/edit

  • 当窗口滚动时,获取垂直滚动距离
    1
    2
    3
    4
    5
    6
    <script>
    $('.content').on('scroll',function(){
    var num = $('.content').scrollTop()
    $('span').text(num)
    })
    </script>

效果预览:http://js.jirengu.com/bajivefije/1/edit

  • 当鼠标放置到$div 上,把$div 背景色改为红色,移出鼠标背景色变为白色
    1
    2
    3
    4
    5
    6
    7
    8
    <script>
    var $box = $('.box')
    $box.on('mouseenter',function(){
    $(this).css('background','red')
    }).on('mouseleave',function(){
    $(this).css('background','white')
    })
    </script>

效果预览:http://js.jirengu.com/tayoxeyeye/1/edit

  • 当鼠标激活 input 输入框时让输入框边框变为蓝色,当输入框内容改变时把输入框里的文字小写变为大写,当输入框失去焦点时去掉边框蓝色,控制台展示输入框里的文字
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <script>
    var $input = $('.ipt')
    $input.focus(function(){
    $(this).css('border-color','blue')
    .on('keyup',function(){
    $(this).val($(this).val().toUpperCase())
    })
    })
    $input.blur(function(){
    $(this).css('border-color','black')
    console.log($(this).val())
    })
    </script>

效果预览:http://js.jirengu.com/likesomeca/1/edit

  • 当选择 select 后,获取用户选择的内容
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    //html
    <select>
    <option value="1">item 1</option>
    <option value="2">item 2</option>
    <option value="3">item 3</option>
    <option value="4">item 4</option>
    <option value="5">item 5</option>
    </select>
    <p>用户选取的内容是:<span>item</span></p>

    //js
    $('select').on('change', function () {
    $('span').text($('select>option:selected').text())
    })

效果预览:http://js.jirengu.com/budugazave/1/edit

题目8: 用 jQuery ajax 实现如下效果。当点击加载更多会加载数据展示到页面效果预览

github代码

本地mock成功.gif

13 jQuery

发表于 2017-12-26 | 分类于 JavaScript

题目1: jQuery 能做什么?

jQuery是一个快速、简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架)。jQuery设计的宗旨是“write Less,Do More”,即倡导写更少的代码,做更多的事情。它封装JavaScript常用的功能代码,提供一种简便的JavaScript设计模式,优化HTML文档操作、事件处理、动画设计和Ajax交互。

jQuery的核心特性可以总结为:具有独特的链式语法和短小清晰的多功能接口;具有高效灵活的css选择器,并且可对CSS选择器进行扩展;拥有便捷的插件扩展机制和丰富的插件。jQuery兼容各种主流浏览器,如IE 6.0+、FF 1.5+、Safari 2.0+、Opera 9.0+等。

jQuery库为Web脚本编程提供了通用(跨浏览器)的抽象层,使得它几乎适用于任何脚本编程的情形。jQuery通常能为我们提供以下功能:

1.方便快捷获取DOM元素

如果使用纯JavaScript的方式来遍历DOM以及查找DOM的某个部分编写很多冗余的代码,而使用jQuery只需要一行代码就足够了。例如,找到所有应用了.content class样式的div中所有的P标签,只需要下面的一行代码:

1
$('div.content').find('p');

2.动态修改页面样式

使用jQuery我们可以动态的修改页面的CSS即使在页面呈现以后。jQuery仍然能够改变文档中某个部分的类或者个别的样式属性。例如,找到页面所有的ul标签的第一个li子标签,然后为它们增加名为active的样式,代码如下:

1
$('ul > li:first').addClass('active');

3.动态改变DOM内容

使用jQuery我们可以很容易地对页面DOM进行修改,例如,为ID为”container”的元素添加一个链接:

1
$('#container').append('<a href="more.html">more</a>');

4.响应用户的交互操作

jQuery提供了截获形形色色的页面事件(比如用户单击某个链接)的适当方式,而不需要使用事件处理程序拆散HTML代码。此外,它的事件处理API也消除了经常困扰Web开发人员浏览器的不一致性。

1
2
3
$('button.show-details').click(function() {
$('div.details').show();
});

上面的代码表示:为使用的.show-details样式的button元素添加一个click事件,事件就是:显示使用.details样式的DIV。

5.为页面添加动态效果

jQuery中内置的一批淡入、擦除之类的效果,以及制作新效果的工具包,为此提供了便利。

1
2
3
4
5
1    $(function () {
2 $("#btnShow").click(function () {
3 $("#msubject").hide("slow");
4 });
5 });

6.统一Ajax操作

jQuery统一了多种浏览器的Ajax操作,使得开发人员更多的专注服务器端开发。

1
2
3
4
1 function (data, type) {
2 // 对Ajax返回的原始数据进行预处理
3 return data // 返回处理后的数据
4 }

7.简化常见的JavaScript任务

除了这些完全针对文档的特性之外,jQuery也改进了对基本的JavaScript数据结构(例如迭代和数组操作等)。

1
2
3
1 $.each(obj, function(key, value) {
2 total += value;
3 });

题目2: jQuery 对象和 DOM 原生对象有什么区别?如何转化?

1.联系:

  • jQuery对象可以通过jQuery包装DOM对象后产生
  • DOM对象也可以通过jQuery按索引取得

2.区别

  • 1.jQuery 对象是通过 jQuery 包装DOM 对象后产生的对象。jQuery 对象是 jQuery 独有的,其可以使用 jQuery 里的方法,但是不能使用 DOM 的方法;例如: $("#img").attr("src","test.jpg"); 这里的$("#img")就是 jQuery对象。
  • 2.DOM对象就是Javascript 固有的一些对象操作。DOM 对象能使用Javascript 固有的方法,但是不能使用 jQuery 里的方法。例如:document.getElementById("img").src = “test.jpg";这里的document.getElementById("img")就是DOM 对象。
    $("#img").attr("src","test.jpg");和document.getElementById("img").src = "test.jpg";是等价的,但是 $("#img").src = "test.jpg" ;或者 document.getElementById("img").attr("src","test.jpg");都是错误的。

3.转换

  • DOM对象转成jQuery对象
    对于已经是一个 DOM 对象,只需要用$()把DOM对象包装起来,就可以获得一个 jQuery 对象了,$(DOM 对象) 注: var是定义变量
    如:
    1
    2
    1 var a = document.getElementById('a'); //DOM对象
    2 var $a = $(a); //jQuery对象

转换后,就可以任意使用jQuery的对象

  • jQuery对象转成DOM对象
    两种转换方式将一个 jQuery 对象转换成 DOM 对象: [index] 和 .get(index);

(1)jQuery对象是一个数组对象,可以通过[index]的方法,来得到相应的DOM对象
如:

1
2
3
1 var $a = $('#a'); //jQuery 对象
2 var a = $a[0]; //DOM对象
3 alert(a.checked); //检测这个checkbox是否被选中

(2) jQuery本身提供,通过.get(index)方法得到相应的DOM

1
2
3
1 var $v = $("#v"); //jQuery 对象
2 var v = $v.get(0); //DOM对象 ( $v.get()[0] 也可以 )
3 alert(v.checked); //检测这个 checkbox 是否被选中

总结:通过以上方法,可以任意的相互转换 jQuery 对象和 DOM 对象,需要再强调的是: DOM 对象才能使用DOM 中的方法,jQuery 对象是不可以使用DOM中的方法。

题目3:jQuery中如何绑定事件?bind、unbind、delegate、live、on、off都有什么作用?推荐使用哪种?使用on绑定事件使用事件代理的写法?

  • jQuery中使用on方法绑定事件,用off方法卸载事件

    • bind、unbind、delegate、live都是jQuery1.7之前的方法,现已废弃,被on和off代替.
    • bind和on都用于绑定事件
    • unbind和off都用于卸载事件
    • delegate与on都可实现事件代理
    • live和bind绑定事件是一样的,但live方法会绑定相应的事件到document元素上
  • 推荐使用on方法绑定事件,off方法卸载事件

  • 用on事件使用事件代理的写法
    1
    .on( events [,selector ] [,data ], handler(eventObject) )

如例:添加一个事件处理函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/ 普通事件绑定,最简单的用法
$('div').on('click', function(e){
console.log(this);
console.log(e);
})

// 事件委托或者事件代理,想让div 下面所有的span绑定事件,可以把事件绑定到div上
$('div').on('click', 'span', function(e){
console.log(this);
console.log(e);
});

// 可以在绑定的时候给事件处理程序传递一些参数
$('div').on('click', {name: 'Byron', age: 24}, function(e){
console.log(e.data);

  • 用off解绑事件使用事件代理的写法
    1
    .off( events [, selector ] [, handler ] )

示例:移除一个事件处理函数

1
2
3
4
5
6
7
8
9
10
11
12
13
function aClick() {
$("div").show().fadeOut("slow");
}

$("#bind").click(function () {
$("body").on("click", "#theone", aClick)
.find("#theone").text("Can Click!");
});

$("#unbind").click(function () {
$("body").off("click", "#theone", aClick)
.find("#theone").text("Does nothing...");
});

  • trigger,根据绑定到匹配元素的给定的事件类型执行所有的处理程序和行为
    1
    2
    3
    4
    $('#foo').on('click', function() {
    console.log($(this).text())
    });
    $('#foo').trigger('click')

示例:创建一个点击事件并模拟点击执行

1
2
3
4
$('#foo').on('click', function() {
alert($(this).text());
});
$('#foo').trigger('click');

题目4:jQuery 如何展示/隐藏元素?

  • 通过设置css的display属性来实现

    1
    2
    3
    var $h1 = $('h1')
    $h1.css('display','block')
    $h1.css('display':'none')
  • 通过增加或删除class来实现

    1
    2
    3
    4
    5
    6
    7
    8
    //css部分
    .status{
    display: none;
    }
    //js部分
    var $h1 = $('h1')
    $h1.addClass('status') //隐藏元素
    $h1.removeClass('status') //展示元素
  • 通过jQuery动画的hide、show、toggle方法实现

    1
    2
    3
    4
    var $h1 = $('h1')
    $h1.hide() //隐藏
    $h1.show() //展示
    $h1.toggle() //用于切换元素的隐藏显示

题目5: jQuery 动画如何使用?

四个参数:
duration:动画持续多久
easing:表示过渡使用哪种缓动函数,jQuery自身提供”linear” 和 “swing”
complete:在动画完成时执行的函数
opacity:不透明度

  • 基础用法:

    • 隐藏元素
      .hide([duration ] [,easing ] [,complete ])
    • 显示元素
      .show( [duration ] [, easing ] [, complete ])
    • 切换元素
      .toggle( [duration ] [, easing ] [, complete ])
  • 渐变

    • 淡入显示
      .fadeIn( [duration ] [, easing ] [, complete ] )
    • 淡出隐藏
      .fadeOut( [duration ] [, easing ] [, complete ] )
    • 调整匹配元素的透明度,方法通过匹配元素的不透明度做动画效果
      .fadeTo( duration, opacity [, easing ] [, complete ] )
    • 调整匹配的元素的不透明度动画来显示或隐藏它们,方法执行匹配元素的不透明度动画。当被可见元素调用时,元素不透明度一旦达到0,display样式属性设置为none ,元素不再影响页面的布局。
      .fadeToggle( [duration ] [, easing ] [, complete ] )
  • 滑动

    • 滑动显示,方法将给匹配元素的高度的动画,这会导致页面的下面部分滑下去,弥补了显示的方式
      .slideDown( [duration ] [, easing ] [, complete ] )
    • 滑动隐藏,方法将给匹配元素的高度的动画,这会导致页面的下面部分滑上去,当一个隐藏动画后,高度值达到0时,display 样式属性被设置为none,该元素不再影响页面布局。
      .slideUp( [duration ] [, easing ] [, complete ] )
    • 用滑动动画显示或隐藏一个匹配元素,方法将给匹配元素的高度的动画,这会导致页面中,在这个元素下面的内容往下或往上滑。display属性值保存在jQuery的数据缓存中,所以display可以方便以后可以恢复到其初始值。
      如果一个元素的display属性值为inline,然后是隐藏和显示,这个元素将再次显示inline。当一个隐藏动画后,高度值达到0的时候,display 样式属性被设置为none,以确保该元素不再影响页面布局。
      .slideToggle( [duration ] [, easing ] [, complete ] )
  • 自定义

    • properties是一个CSS属性和值的对象,动画将根据这组对象移动。
      .animate( properties [, duration ] [, easing ] [, complete ] )
    • options是一组包含动画选项的值的集合。
      animate( properties, options )
    • 当一个元素调用.stop(),当前正在运行的动画(如果有的话)立即停止。
      .stop( [clearQueue ] [, jumpToEnd ] )

题目6:如何设置和获取元素内部 HTML 内容?如何设置和获取元素内部文本?

  • 用html方法获取/修改元素的innerHTML

    • 没有传递参数时直接返回元素的innerHTML
      $('div').html()
    • 传递了一个string参数时修改元素的innerHTML为参数值
      $('div').html('hello world')
  • 用text方法获取/修改元素的innerText

    • 没有传递参数时直接返回元素的innerText
      $('div').text()
    • 传递了一个string参数时修改元素的innerText为参数值
      $('div').text('hello world')

这种读写两用的方法很多,原理都类似

  1. 如果结果是多个,进行赋值操作的时候会给每个结果都赋值

  2. 如果结果多个,获取值的时候,$node.html()返回结果集中的第一个对象的相应值,$node.text()返回结果集中的所有值组成的字符串。

题目7:如何设置和获取表单用户输入或者选择的内容?如何设置和获取元素属性?

  • 用val方法设置和获取表单用户输入或者选择的内容
    也是一个读写双用的方法,用来处理input的value,当方法没有参数的时候返回input的value值,当传递了一个参数的时候,方法修改input的value值为参数值

    1
    2
    $('input').val()//获取用户输入或选择的内容
    $('input').val('newValue');//设置用户输入或选择的内容
  • 用attr和prop方法来设置和获取元素属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    //获取元素属性
    $node.attr('id')
    $node.attr('src')
    //获取元素自定义属性
    $node.prop('data-title')
    //设置元素属性
    $node.attr('id','newId')
    $node.attr('src','newSrc')
    //设置元素自定义属性
    $node.prop({
    data-title: "newTitle",
    data-href: "new href"
    })

    attr多用于html原有属性,prop多用于自定义属性。

题目8:使用 jQuery实现如下效果


代码实现(http://js.jirengu.com/boyinuqiwi/5/edit)

题目9:. 使用 jQuery 实现如下效果


代码实现(http://js.jirengu.com/wuxes/5/edit)

题目10:实现如下效果


代码实现(http://js.jirengu.com/kafefewopu/2/edit)

题目11: 完成 左右切换的 Tab 效果

代码实现(http://js.jirengu.com/hezisujore/2/edit)

12…4
Nie

Nie

Fair to be late, but never absent

32 日志
4 分类
GitHub
© 2017 — 2018 Nie
博客
|
主题 — v5.1.4