1. 课程介绍
- 1. 假继承(没有实现原型链);(了解)
- 2. 真继承(实现了原型链);(掌握)
- 3. 函数的高级使用;(掌握)
- 4. 复习jQuery、事件命名空间、继承;(了解)
- 5. 自定义简单jQuery插件;(掌握)
- 6. 自定义jQuery datagrid插件;(掌握)
- 继承
2.1. 为什么要学习继承
面试,理解其它框架
百度一下 Extjs(写了很多组件的继承),类似于easyui
- 复习Java的继承
3.1. Java继承结构图
3.2. 父类User
public class User {
protected String name;
protected Integer age;
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
3.3. 子类Student
public class Student extends User {
private String no;
Public Student(String name, Integer age, String no) {
// 首行:把子类的name,age属性传递给父类 子类调用父类的构造方法
super(name, age);
this.no = no;
}
- 假继承(没有实现原型链)
JavaScript没有为开发人员提供继承的方法,我们需要手动实现继承;
没有Java的extends继承关键字
4.1. 实现步骤
- 定义好父类和子类,都使用function来定义
- 子类构造函数中去"调用父类的构造函数".如果父类有构造参数需要传入
- 为父类添加自己的原型成员,用于测试效果
- 把父类中的原型对象拷贝到子类的原型对象中
- 为子类添加自己的原型成员,用于测试效果
4.2. 步骤1-2
4.2.1. 定义父类
function User(name) {
this.name = name;
this.getAbc = function() {
return this.name;
}
}
4.2.2. 定义子类
function Student(name, no) {
//this.name = name;没有子类与父类的关系
//1.子类构造函数中去"调用父类的构造函数".如果父类有构造参数需要传入.
// 子类调用父类的有参构造方法
// this===student
//User.call(this, name);
User.apply(this, arguments);
this.no = no;
}
4.3. 步骤3
// 3.为父类添加自己的原型成员,子类应该是继承过来的
User.prototype.getName = function() {
return this.name;
}
User.prototype.age = 20;
4.4. 步骤4
// 4.把父类中原型对象的属性拷贝到子类的原型对象中.
// 方案1:
// Student.prototype = User.prototype;//把子类的原型属性直接赋值父类
// 前者是地址引用,这样修改Student的原型 会直接修改父类User原型,这样不推荐
// 后者是原型属性拷贝,子类相对独立,不会影响父类
for ( var p in User.prototype) {
console.debug("p=" + p);
Student.prototype[p] = User.prototype[p];
}
4.5. 步骤5
// 5.为子类添加自己的原型成员
Student.prototype.getNo = function() {
return this.no;
}
4.6. 步骤6:测试
var user = new User("张二娃");
var student = new Student("王九蛋", 12345);
console.dir(user);
console.debug("-----------------");
console.dir(student);
console.debug(student instanceof User);// false
- 真继承(实现了原型链)
5.1. 其实JS中的继承就是使用的一个原型链
如果一个对象的原型对象上面还有原型对象,那么这个对象就相当于继承了原型对象上面的原型对象的类.
var student = new Student("xxx", 25, 200);
例如: 如果一个对象student 的原型对象Student.prototype(等价于studnet.__proto__)上面还有原型对象User.prototype,那么这个对象student 就相当于继承了原型对象Student.prototype上面的原型对象User.prototype的类User.
如日期对象 Date prototype ==》Object prototype
5.2. 标准的原型链继承链
Student prototype ==》User prototype ==》Object prototype
5.3. 完整代码
//定义父类
function User(name) {
this.name = name;
this.getName = function() {
return this.name;
}
}
//定义子类
function Student(name, no) {
//this.name = name;没有子类父类的关系
//1.子类构造函数中去"调用父类的构造函数".如果父类有构造参数需要传入.
// 子类调用父类的有参构造方法
// this===student
//User.call(this, name);
User.apply(this, arguments);
this.no = no;
}
// 2.为父类添加自己的原型成员,子类应该是继承过来的
User.prototype.getName = function() {
return this.name;
}
User.prototype.age = 20;
// 3.把父类中原型对象的属性拷贝到子类的原型对象中.
// 方案1:这是一个野方法,只能在个别浏览器下面运行(SB IE无法运行). 最简单实用,但是兼容性问题
// Student.prototype.__proto__ = User.prototype;
//方案2:Student prototype(原型名称是User) ==》User prototype ==》Object prototype
// Student.prototype = new User();
//方案3:Student prototype ==》User prototype ==》Object prototype
// 必须支持ECMAScript5规范
//Object.create根据参数User.prototype来创建原型User.prototype
Student.prototype = Object.create(User.prototype);
//上一行代码替换Student的原型,并且把constructor构造函数替换了,所以我们需要替换回来.
//constructor: User(name)替换成constructor: Student(name,no)
//修改Student构造方法的名称
Student.prototype.constructor = Student;
// 4.为子类添加自己的原型成员
Student.prototype.getNo = function() {
return this.no;
}
var user = new User("张二娃");
var student = new Student("王九蛋", 12345);
console.dir(user);
console.debug("-----------------");
console.dir(student);
console.debug(student instanceof User);// true
- 函数的高级使用
6.1. 回调函数
回调函数:回调函数就是一个通过函数指针调用的函数。如果你把函数的引用(地址)作为参数传递给另一个函数,当这个引用被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
回调函数就是一个通过函数(对象)引用调用的函数;
//添加了一个定时器,延迟1秒打印1
setTimeout(function() {
console.debug(1);
}, 1000);
//打印2
console.debug(2);
// 上面使用的是回调函数也是匿名函数
// 下面就把匿名函数改为有名字的函数
//该函数等time毫秒后执行一段代码.
function fn(){
alert("你行不行我分分钟终结你");
alert("噹噹噹....");
}
setTimeout(fn,3000);
6.2. 匿名函数:没有定义名称的函数
一般这种函数作为值进行传递到某一个函数中或者是赋给其他变量。
匿名函数作用:还可以包含一段代码,然后直接调用执行,避免产生全局变量。
setTimeout(function(){
console.debug("aaaaaaaaaaaaaaa");
},1000);
/*
以下代码会导致全局变量中始终都存在x,y,而x和y计算后就不需要了,这种情况我们称为作用域污染.
var x = 10;
var y = 50;
var result = x*y;
console.debug(window);
*/
/**
匿名函数写法:
(function(){
//推荐写法
})(); //自执行函数
~function(){//可以在jQuery1.3版本上面看到
}
**/
//推荐写法
(function(x,y){
window.result = x*y; //添加全局作用域中.
})(10,50);
如果不写匿名函数外面的(),出现语法错误。。。
jQuery的源码就是这样写出来的
6.3. 闭包
闭包,指的是语法表示包括不被计算的变量的函数,
也就是说,函数中可以使用函数之外定义的变量,封装特性
6.3.1. 闭包第一种用法:函数中可以使用函数之外定义的变量。
var msg = "呵呵";
function sayMsg(){
//函数中可以使用函数之外定义的变量。
console.debug(msg);
}
sayMsg();
6.3.2. 闭包第二种用法:通过闭包实现只读属性
function User(name, age) {
//以下代码都不能这样写了
// this.name = name;
// this.age = age;
//实现一个功能:name,age是只读属性
this.getName=function(){
return name;
};
this.getAge=function(){
return age;
}
}
var user = new User("史珍香", 20);
user.name = "xxx";//新增的一个属性,和传入的史珍香没有关系
console.debug(user.getName());
console.debug(user.getAge());
console.debug(user.name);
- 复习jQuery-选择器、事件监听
<script type="text/javascript" src="jquery-2.1.1.min.js"></script>
<script type="text/javascript">
//jQuery的代码必须写在页面body加载完成之后
$(function() {
//选择器
$("#xxx").html("yyy");
$(".mydiv").html("zzz");
//监听事件的方式:一般都使用前面2种方式
$("#xxx").click(function() {
console.debug(1);
});
$("#xxx").on('click', function() {//取消事件监听 off
console.debug(2);
});
$("#xxx").bind('click', function() {//取消事件监听 unbind
console.debug(3);
});
// 了解:如果监听的控件是某个小区域,先监听大的区域,添加一个过滤的条件(选择器)
$("body").on('click','.mydiv', function() {
console.debug(2);
});
});
</script>
</head>
<body>
<div id="xxx" class="mydiv">xxx</div>
</body>
- jQuery事件命名空间
<script type="text/javascript" src="jquery-2.1.1.min.js"></script>
<script type="text/javascript">
//jQuery的代码必须写在页面body加载完成之后
$(function() {
$("#xxx").on('click', function() {
console.debug(1);
});
//只监听一次点击事件,然后取消监听
//click事件名称.manager命名空间
$("#xxx").on('click.manager', function() {//取消事件监听 off
console.debug(2);
$("#xxx").off('click.manager');
});
});
</script>
</head>
<body>
<div id="xxx">xxx</div>
</body>
- jQuery继承
<script type="text/javascript" src="jquery-2.1.1.min.js"></script>
<script type="text/javascript">
//jQuery.extend([deep], target, object1, [objectN])
//1.json的属性的抽取
//使用场景:上传身份证照片:正面,背面
var config = {
url : "upload.action",
xxx:"yyy"
};
//先传入目标对象的jspn,公共对象放在后面
var config1 = jQuery.extend({
name : "pic1"
}, config);
var config2 = jQuery.extend({
name : "pic2"
}, config);
console.debug(config1);
console.debug(config2);
//2.jquery原型进行扩展.
$.fn.extend({
myplugin1:function(){
},
myplugin2:function(){
}
});
//以上效果等同于
//$.fn.myplugin1 = function(){};
//$.fn.myplugin2 = function(){};
</script>
- 简单jQuery插件
<title>简单jQuery插件</title>
<style type="text/css">
.mydiv {
background-color: red;
100px;
height: 100px;
}
.mydiv2 {
background-color: yellow;
200px;
height: 200px;
}
</style>
<script type="text/javascript" src="jquery-2.1.1.min.js"></script>
<script type="text/javascript">
$(function() {
$.fn.plugin = function(cls) {
$(this).hover(function() {
//添加样式
$(this).addClass(cls);
},function() {
//移除样式
$(this).removeClass(cls);
});
}
//插件的用法就是用jQuery的方法一样
$("#mydiv").plugin("mydiv2");
});
</script>
</head>
<body>
<div id="mydiv" class="mydiv">000</div>
</body>
- jQuery自定义插件datagrid
显示表格数据的插件
11.1. 效果
11.2. DatagridAction
@Controller
@Scope("prototype")
public class DatagridAction extends BaseAction {
@Autowired
private IEmployeeService employeeService;
// 显示一个页面,不添加数据
// http://localhost/datagrid.action
@Override
public String execute() throws Exception {
return SUCCESS;
}
// 专门返回json数据
// 应该是发出一个ajax请求 http://localhost/datagrid_json.action
public String json() throws Exception {
// <param name="root">#map</param>
// 只拿前10条
putContext("map", employeeService.getAll().subList(0, 10));
// <result name="json" type="json">
return "json";
}
}
11.3. 修改Employee
必须重启tomcat
@JSON(serialize = false)//roles属性json不输出
public Set<Role> getRoles() {
return roles;
}
11.4. 步骤1,属性id,username是写死的
<script type="text/javascript" src="assets/js/jquery-2.0.3.min.js"></script>
<script type="text/javascript">
$(function() {
$.fn.datagrid = function(json) {
var url = json.url;
//创建插件的时候,已经传入url地址
if (url) {
//获取table的jQuery对象,存起来
var table = $(this);
$.get(url, function(data) {
console.debug(data.length);//10
for (var i = 0; i < data.length; i++) {
var tr = "<tr>";
tr+="<td>"+data[i].id+"</td>";
tr+="<td>"+data[i].username+"</td>";
tr+="</tr>";
table.append(tr);
}
});
}
};
$("#dg").datagrid({
url : "datagrid_json.action"
});
});
</script>
<title>问题点:属性id,username是写死的</title>
</head>
<body>
<table id="dg" border="1">
<tr>
<th>编号</th>
<th>用户名</th>
</tr>
</table>
</body>
11.5. 步骤2,年龄,头像,部门不能额外处理
以下代码不能把大于25岁的年龄标红,头像不能显示(只有路径),部门名称显示不了
<script type="text/javascript" src="assets/js/jquery-2.0.3.min.js"></script>
<script type="text/javascript">
$(function() {
$.fn.datagrid = function(json) {
var url = json.url;
//创建插件的时候,已经传入url地址
if (url) {
//获取table的jQuery对象,存起来
var table = $(this);
//获取所有的th
var ths = table.find("tr th");
console.debug(ths.length);//3
$.get(url, function(data) {
console.debug(data.length);//10
for (var i = 0; i < data.length; i++) {
var tr = "<tr>";
for (var j = 0; j < ths.length; j++) {
//获取th里面定义的属性field
var field = $(ths[j]).attr("field");
tr+="<td>"+data[i][field]+"</td>";
}
tr+="</tr>";
table.append(tr);
}
});
}
};
$("#dg").datagrid({
url : "datagrid_json.action"
});
});
</script>
<title>问题点:年龄,头像,部门额外处理不行</title>
</head>
<body>
<table id="dg" border="1">
<tr>
<th field="id">编号</th>
<th field="username">用户名</th>
<th field="password">密码</th>
<th field="email">邮箱</th>
<th field="age">年龄</th>
<th field="headImage">头像</th>
<th field="department">部门</th>
</tr>
</table>
</body>
11.6. 步骤3,判断age,headImage,department都是写死的
if("age"==field && data[i][field]>25){
tr += "<td style='color:red'>" + data[i][field] + "</td>";
}else if("headImage"==field){
tr += "<td><img src='"+data[i][field]+"'></td>";
}else if("department"==field){
tr += "<td>" + data[i][field]["name"] + "</td>";
}else{
tr += "<td>" + data[i][field] + "</td>";
}
11.7. 步骤4,最终版本
<script type="text/javascript" src="assets/js/jquery-2.0.3.min.js"></script>
<script type="text/javascript">
$(function() {
$.fn.datagrid = function(json) {
var url = json.url;
//创建插件的时候,已经传入url地址
if (url) {
//获取table的jQuery对象,存起来
var table = $(this);
//获取所有的th
var ths = table.find("tr th");
console.debug(ths.length);//3
$.get(url, function(data) {
console.debug(data.length);//10
for (var i = 0; i < data.length; i++) {
var tr = "<tr>";
for (var j = 0; j < ths.length; j++) {
//获取th里面定义的属性field
var field = $(ths[j]).attr("field");
//获取th里面定义的属性format
var format = $(ths[j]).attr("format");
if(format ){
//调用window的函数,函数名是一个变量,当前的函数名有ageFarmat
tr+="<td>"+window[format ](data[i][field])+"</td>";
}else{
tr+="<td>"+data[i][field]+"</td>";
}
}
tr+="</tr>";
table.append(tr);
}
});
}
};
$("#dg").datagrid({
url : "datagrid_json.action"
});
});
//必须写在最外面
function ageFormat(value){
return value&&value>25?"<font color='red'>"+value+"</font>":value;
}
function imageFormat(value){
return value?"<img src='"+value+"'/>":"";
}
function deptFormat(value){
return value?value.name:"";
}
</script>
<title>最终版</title>
</head>
<body>
<table id="dg" border="1">
<tr>
<th field="id">编号</th>
<th field="username">用户名</th>
<th field="password">密码</th>
<th field="email">邮箱</th>
<th field="age" format ="ageFormat">年龄</th>
<th field="headImage" format="imageFormat">头像</th>
<th field="department" format="deptFormat">部门</th>
</tr>
</table>
</body>
- 课程总结
12.1. 重点
- 真继承(实现原型链)
- jQuery选择器,事件监听,命名空间
12.2. 难点
- 闭包
- jQuery自定义datagrid插件
- 常见异常
- 课后练习
- jQuery自定义插件datagrid
- 面试题
- JS继承的实现方式
1、原型链继承
2、构造继承
3、实例继承
4、拷贝继承
5、组合继承
6、寄生组合继承
https://www.cnblogs.com/humin/p/4556820.html
- 继承实现方式:关键就是原型链
Student.prototype.__proto__ = User.prototype;
Student.prototype = Object.create(User.prototype);
- 面试题1
<script type="text/javascript">
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
// this==object
console.debug(this);
var that = this;
return function(){
console.debug(this);
// this==window
return that.name;
};
}
};
console.debug(object.getNameFunc()());
</script>
//1.调用了2次函数
//2.第1步执行object.getNameFunc()返回是什么?匿名函数
// function(){
// return function(){
// return that.name;
// };
// }
// 2.第2步执行执行第1步的函数:object.getNameFunc()()
console.debug(object.getNameFunc()());
- 面试题2
<script type="text/javascript">
var b = function() {
console.debug(123);
return function() {
console.debug(1234);
}
}
console.debug(b()());
//1.函数要执行2次
// 步骤1:调用b() --->打印123
// 步骤2:调用b()() -->打印1234
// 步骤3:拿到里面函数的返回值--> 打印undefined
</script>
16.1. 扩展知识
- 百度一下 javasript 继承
- 百度一下 ECMAScript5规范,最新版本简称es6规范,javascript的规范