JavaScript高级-ES6
一、ECMAScript简介
·ECMA(European Computer Manufactures Association)中文名称为欧洲计算机制造商协会
·ECMAScript是由ECMA国际通过ECMA-262标准化的脚本程序设计语言
·Ecma国际制定了许多标准,而ECMA-262只是其中一个,所有标准列表查看
http://www.ecma-international.org/publications/standards/Standard.htm
二、ECMA-262历史
三、为什么要学习ES6
·ES6的版本变动内容最多,具有里程碑意义
·ES6加入许多新的语法特性,编程实现更简单、高效
·ES6是前段发展趋势,就业必备技能
四、let关键字
let关键字用来声明变量,使用let声明的变量有几个特点:
·不允许重复声明
·块级作用域
·不存在变量提升
·不影响作用域链
应用场景:以后声明变量使用 let 就对了
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//let关键字
/*
特点:
*1.不允许重复声明
*2.块级作用域
*3.不存在变量提升
*4.不影响作用域链
应用场景:
*声明变量使用let就对了
*/
//console.log(a);//Cannot access 'a' before initialization a变量不能再声明之前使用
let a=10;
//let a=20; //Identifier 'a' has already been declared 不能重复声明
if(true){
let b=10;
}
//console.log(b)//ReferenceError: b is not defined 具有块级作用域
</script>
</body>
</html>
五、const关键字
const关键字用来声明变量,const声明有以下特点
·声明必须赋初始值
`标识符一般大写
·不允许重复声明
·块级作用域
注意: 对象属性修改和数组元素变化不会触发 const 错误 应用场景:声明对象、数组类型、以及常量时使用 const,非对象类型声明选择 let
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//const关键字
/*
特点:
*1.声明必须赋初始值
*2.标识符一般为大写
*3.不允许重复声明
*4.值不允许被修改
*5.块级作用域
*/
//注意:对象属性修改和数组元素变化不会触发const错误
//应用场景:声明对象、数组类型、以及常量时使用const,非对象类型声明选择let
//const a;//Missing initializer in const declaration 没有设置初始值
const b=12;
///const b="ff";//Identifier 'b' has already been declared 不能重复声明
console.log(b)
//b=15;//Assignment to constant variable. 不允许修改值
if(true){
const c=1001;
}
//console.log(c)//ReferenceError: c is not defined 没有定义
const arr=[1001,"张三"]
console.log(arr)// [1001, '张三']
arr[1]="李四";
console.log(arr)//[1001, '李四']
</script>
</body>
</html>
var关键字
var关键字用来声明变量,var声明有以下特点
1.var变量会挂载在Window上
2.var变量声明存在变量提升
3.var变量可以声明同名变量
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//var变量
/*
特点
*1.var变量会挂载在Window上
*2.var变量声明存在变量提升
*3.var变量可以声明同名变量
*/
console.log(a)//undefined
var a=10;
if(true){
var b=12;
}
console.log(b)//12
var a="fff";
console.log(a)//fff
</script>
</body>
</html>
六 、变量的解构赋值
ES6允许按照一定模式,从数组和对象中提取值,这被称为解构赋值
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//数组的解构赋值
const arr=["张学友","刘德华","黎明","郭富城"]
let [zhang,liu,li,guo]=arr
console.log(li)
//对象的解构赋值
const lin={
name:"林志颖",
tags:["车手","歌手","小旋风","演员"]
}
let newobj={name, tags}=lin;
console.log(name)
//复杂解构赋值
let wangfei = {
name: '王菲',
age: 18,
songs: ['红豆', '流年', '暧昧', '传奇'],
history: [ { name: '窦唯' }, { name: '李亚鹏' }, { name: '谢霆锋' }
]};
let {songs:[one,tow,three],history:[fist,second,tiird]}=wangfei
console.log(one,tow,three);//songs
console.log(fist,second,tiird)//history
</script>
</body>
</html>
七、 模板字符串
模板字符串(template string)是增强版的字符串,用反引导(`)标识,特点:
·字符串中可以出现换行符
·可以使用$(xxx)形式输出变量
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const arr=["张学友","刘德华","黎明","郭富城"]
let [zhang,liu,li,guo]=arr
//定义字符串
let str=`
<ul>
<li>${zhang}</li>
<li>${liu}</li>
<li>${li}</li>
<li>${guo}</li>
</ul>
`;
document.querySelector('body').innerHTML=str;
</script>
</body>
</html>
注意:当遇到字符串与变量拼接的情况使用模板字符串
八、简化对象写法
ES6允许在大括号里面,直接写入变量和函数,作为对象的属性和方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//简化对象写法
/*
ES6 允许在大括号里面,直接写入变量和函数,
作为对象的属性和方法。这样的书写更加简洁
*/
let name="fxt";
let text="大数据1801班";
let improve=function(){
console.log("可以学习VueJs")
}
//属性和方法简写
let newobj={
name,
text,
improve
}
console.log(newobj)
//注意:对象简写形式简化了代码,所以以后用简写就对了
</script>
</body>
</html>
注意:对象简写形式简化了代码,所以以后用简写就对了
九、箭头函数
ES6允许使用[箭头](=>)定义函数
箭头函数的注意点:
·如果形参只有一个,则括号可以省略
·函数体如果只有一条语句,则花括号可以省略,函数的返回值为该条语句的执行结果
·箭头函数this指向声明时所载作用域下this的值
·箭头函数不能作为构造函数实例化
·不能使用arguments
箭头函数的基本使用:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//箭头函数
/*
ES6 允许使用「箭头」(=>)定义函数
箭头函数的注意点:
1.如果形参只有一个,则小括号可以省略
2.函数体如果只有一个语句,则花括号可以省略,
函数的返回值为该条语句的执行结果
3.箭头函数this指向声明时所载作用域下this的值
4.箭头函数不能作为构造函数实例化
5.不能使用arguments
*/
let fun2=function (c,d){
return c+d;
}
console.log(fun2(10,12))
//1.通用写法
let fun1=(a,b)=>{
return a+b;
}
console.log(fun1(3,4))
</script>
</body>
</html>
箭头函数的方法体变化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// let sum=(a,b)=>{
// return a+b;
// }
// console.log(sum(2,15))//17
// 当方法体代码只有一行时,就可以省略{},如果有返回值,return也可以省略
let fun1=(a,b)=>console.log(a,b);//没有return
fun1(2,3)
let fun2=(a,b)=> a+b;//有返回值
console.log(fun2(2,3))
</script>
</body>
</html>
箭头函数的this
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//箭头函数函数本身是没有this指向的,由外部this决定的 谁调用就属于谁
//this => object window undefined
//console.log(this);//window
const obj={
name:'张三',
age:18,
sayHi:function(){
console.log(this)//对象内部函数的this指向对象本身
setTimeout(()=>{
console.log(this)//obj
},1000)
setTimeout(()=>{},1000)
}
}
obj.sayHi();
</script>
</body>
</html>
注意:箭头函数不会更改 this 指向,用来指定回调函数会非常合适
十、rest参数
ES6引入rest参数,用于获取函数的实参,用来代替arguments
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const nums=function add(a,b,...args){
console.log(args)//3,4,5,6,7,8,9,10
}
nums(1,2,3,4,5,6,7,8,9,10)
</script>
</body>
</html>
注意: rest 参数非常适合不定个数参数函数的场景
十一、spread扩展运算符
扩展运算符(spread)也是三个点(...)。它好比rest参数的逆运算,将一个数组转为用逗号分隔的参数序列,对数组进行解包
例如:数组
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// ... spread运算符、扩展运算符、展开运算符
let lianmeng=['德玛西亚之力','德玛西亚之翼','德玛西亚皇子'];
const foo=(a,b,c)=>{
console.log(a,b,c);
}
foo(...lianmeng);
const a=['h','o','l','l','e']
const b=['w','o','r','l','d']
const c=[...a,...b]
console.log(c)
</script>
</body>
</html>
对象
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const obj={
name:"张三",
name:"李四"
}
console.log(obj)//objec=>name:"李四"
let obj1={
name:"张三",
age:18,
height:168
}
let obj2={
name:"李四",
gender:"男"
}
const newobj={...obj1,...obj2,name:"王五"}
console.log(newobj)//{name: '王五', age: 18, height: 168, gender: '男'}
</script>
</body>
</html>
十二、Promise
·promise是ES6引入的异步编程的新解决方案
·语法上promise是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果
·promise构造函数:promise(excutor){ }
·promise.prototype.then方法
·promise.prototype.catch方法
·promise.prototype.all
例如:为什么有promise(使用函数封装的方法得到上一步请求的数据)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//** 登录 验证账号和密码 =>成功 返回了uid */
$.ajax({
url:"/getId",
method:"Post",
data:{},
success:function(){
getId(10);
}
})
//通过函数去得到上一次请求返回的数据
//通过登录ID得到此id的用户信息
function getId(id){
$.ajax({
url:"/getId",
method:"Post",
data:{
id:id
},
success:function(info){
getIdInfo(info);
}
})
}
//通过得到的用户信息得到用户的RoleId
function getIdInfo(info){
$.ajax({
url:"/getinfo",
method:"Post",
data:{
Role:info.Roleid
},
success:function (){
//请求成功时要执行的函数体
}
})
}
</script>
</body>
</html>
例如:为什么有promise(ajax套嵌—回调地狱)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// ajax 中套ajax => 回调地狱
// 登录 验证账号和密码 =>成功 返回了uid id
// 根据uid 获取你的用户信息=>返回了用户信息 roleId
// 根据你用户信息中的角色id 获取你的角色(权限) permissionsId
// 根据你的权限 在做某些事情
/** 登录 验证账号和密码 =>成功 返回了uid */
$.ajax({
url:"/getId",
method:"Get",
data:{},
success:function (response) {
// response = id 根据id去获取你的用户信息
/** 根据uid 获取你的用户信息=>返回了用户信息 */
$.ajax({
url:"/getInfo",
method:"Get",
data:{
id:response.id
},
success:function (info) {
// 用户信息中有角色 role
/** 根据你用户信息中的角色id 获取你的角色(权限) */
$.ajax({
url:"/getRole",
method:"Get",
data:{
role:Role.id
},
success:function(Info){
/** 根据你的权限 在做某些事情 */
$.ajax({
url:"/getInfo",
method:"Get",
data:{
roleId:info.roleId
},
success:function(){
}
})
}
})
}
})
}
})
</script>
</body>
</html>
例如:promise的基本使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
// Promise的结果会走then和catch
// 决定走then和走catch 是由resolve和reject决定的
// new Promise(fn)
// resolve 成功的回调函数 => 最终结果就使用then
// reject 失败的回调函数=> 最终结果就使用catch
const p=new Promise((resolve,reject)=>{
const a=9;
if(a==10){
//成功时的回调函数
resolve(a);
}else{
//失败时的回调函数
reject(a);
}
});
//成功
// p.then(res=>{
// console.log(res)
// })
// //失败
// p.catch(err=>{
// console.log(err)
// })
p.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
</script>
</body>
</html>
例如:promise的连续使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
const p1=new Promise((resolve,reject)=>{
const num=Math.round(Math.random()*10000)
if(num%2==0){
resolve({
num,
info:"num是偶数"
})
}else{
reject({
num,
info:"num是奇数"
})
}
})
const p2 = p1.then(res=>{
console.log(res)
return new Promise((resolve,reject)=>{
resolve(res.num/2)
})
}).catch(err=>{
console.log(err)
return new Promise((resolve,reject)=>{
reject(err.num*2)
})
})
p2.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
</script>
</body>
</html>
例如:promise改造函数封装的ajax请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
function getId(){
new Promise((resolve,reject)=>{
$.ajax({
url:"/getid",
method:"Post",
data:{},
success:function(){
resolve(10)
},
error:function(){
reject("请求失败")
}
});
});
};
function getInfo(){
new Promise((resolve,reject)=>{
getId().then(res=>{
$.ajax({
url:"/getinfo",
method:"Post",
data:{
id:res
},
success:function(){
resolve(info)
},
error:function(){
reject("失败")
}
})
})
})
}
function getRoleId(){
new Promise((resolve,reject)=>{
getInfo().then(res=>{
$.ajax({
url:"getinfo",
method:"Post",
data:{
roleId:info.id
},
success:function(){
//成功后要执行的事情
},
error:function(){
//失败后要执行的事情
}
})
})
})
}
</script>
</body>
</html>
例如:promise封装jQueryAjax
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>
<title>Document</title>
</head>
<body>
<script>
function http(config){
return new Promise((resolve,reject)=>{
const {url,method,data}=config
$.ajax({
url,
method,
data,
success:function(response){
resolve(response)
}
})
})
}
function category(){
http({
url:"http://119.91.125.14:4000/category",
method:"Get",
}).then(res=>{
console.log(res)
})
}
category();
</script>
</body>
</html>
例如:promise封装原生Ajax
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="http.js"></script>
</head>
<body>
<script>
http({
url:"http://119.91.125.14:4000/category",
method:"GET",
data:{},
success:function(response){
console.log(response)
}
})
const p=$http({
url:"http://119.91.125.14:4000/category",
method:"GET",
data:{}
});
p.then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
</script>
</body>
</html>
十三、 迭代器
什么是迭代器
迭代器(Iterator)就是一种机制。它是一种接口,为各种不同的数据结构提供统一的访问机制。
ES6创造了一种新的遍历命令for....of循环,Iterator接口主要供for...of消费
原生具备iterator接口的数据(可用for of遍历)
Array
Arguments
Set
Map
String
NodeList
工作原理
创建一个指针对象,指向当前数据结构的起始位置
第一次调用对象的 next 方法,指针自动指向数据结构的第一个成员
接下来不断调用 next 方法,指针一直往后移动,直到指向最后一个成员
每调用 next 方法返回一个包含 value 和done 属性的对象
注: 需要自定义遍历数据的时候,要想到迭代器
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<script>
//遍历array
const arr=['a','b','c','d']
for (const item of arr) {
console.log(item)
}
//遍历arguments
function foo(){
console.log(arguments);
for (const item of arguments) {
console.log(item);
}
}
foo(...arr)
//遍历string
for (const item of 'hello world') {
console.log(item)
}
//遍历NOdeList
const lis=document.querySelectorAll('ul>li')
for (const item of lis) {
console.log(item.textContent)
}
</script>
</body>
</html>
set
ES6 提供了新的数据结构 Set(集合)。它类似于数组,但成员的值都是唯一的,集合实现了 iterator 接口,所以可以使用『扩展运算符』和『for…of…』进行遍历,集合的属性和方法:
size 返回集合的元素个数
add 增加一个新元素,返回当前集合
delete 删除元素,返回 boolean 值
has 检测集合中是否包含某个元素,返回 boolean 值
clear 清空集合,返回 undefined
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//创建一个空集合
let Array=new Set();
//创建一个非空的集合
let Array2=new Set([1,2,3,4,5,6]);
//返回几个元素个数
console.log(Array2.size)
//添加新元素
console.log( Array2.add(7));
//删除元素返回Boolean值
console.log(Array2.delete(3));
console.log(Array2)
//检测是否存在某个值
console.log(Array2.has(3));//false
//清空集合返回集合
console.log(Array2.clear())//undefined
</script>
</body>
</html>
Map
ES6 提供了 Map 数据结构。它类似于对象,也是键值对的集合。但是“键” 的范围不限于字符串,各种类型的值(包括对象)都可以当作键。Map 也实现了iterator 接口,所以可以使用『扩展运算符』和 『for…of…』进行遍历。Map 的属性和方法:
size 返回 Map 的元素个数
set 增加一个新元素,返回当前 Map
get 返回键名对象的键值
has 检测 Map 中是否包含某个元素,返回 boolean 值
clear 清空集合,返回 undefined
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//创建一个空 Map
let m = new Map();
//创建一个非空 map
let m2=new Map([['name',"web"],['slogon',"不断提高"]])
//属性和方法
//获取映射元素的个数
console.log(m2.size);
//添加映射值
m2.set('age',18)
console.log(m2);
//获取映射值
console.log(m2.get('age'));
//检测是否有该映射
console.log(m2.has('name'));
//清空集合
m2.clear()
console.log(m2.size);
</script>
</body>
</html>
十四、class类
ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过 class 关键 字,可以定义类。基本上,ES6 的 class 可以看作只是一个语法糖,它的绝大部分功能,ES5 都可以做 到,新的 class 写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。知识点:
class 声明类
constructor 定义构造函数初始化
extends 继承父类
super 调用父级构造方法
static 定义静态方法和属性
父类方法可以重写
例如:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script>
//父类
class father{
//父类构造方法
constructor(brand,color,price){
this.brand=brand;
this.color=color;
this.price=price;
}
//对象方法
call(){
console.log("我可以打电话!!")
}
}
class sun extends father{
brand='';
color;
price;
//子类的构造方法
constructor(brand, color, price){
super(brand, color, price)
}
//子类方法
photo() {
console.log('我可以运行程序')
}
static connect() {
console.log('我可以建立连接')
}
}
//实例化对象
const fatherobj=new father("诺基亚","灰色",230);
fatherobj.call();
const sunobj=new sun("苹果","白色",6800);
sunobj.photo()
sun.connect()
sunobj.call()
</script>
</body>
</html>
static修饰符
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
class father{
data='2021-12-25';
static name="fxt";
//父类构造方法
constructor(brand,color,price){
this.brand=brand;
this.color=color;
this.price=price;
}
//对象方法
call(){
console.log(this)//=>father类 => 不能调用非static修饰的属性和方法
console.log(this.brand+"我可以打电话!!")
}
}
//通过类名直接调用静态方法和静态属性
console.log(father.name);
//console.log(father.data);非静态方法属性不能使用类名调用
const fatherobj=new father("诺基亚","灰色",230);
//注意实例对象不能调用静态方法和静态属性
console.log(fatherobj.name);//undefined
fatherobj.call();
console.log(fatherobj.data);
</script>
</html>