目录
2.直接通过函数名调用函数时,this指向全局对象window
2.ES5的继承:通过原型对象实现(将父类的实例对象赋给子类的原型对象)
(2)isPrototypeOf()方法:判断原型对象的类型
一、类的创建
1.ES5
class 类名{
}
2.ES6
(1)class类名
class类名{
构造函数([参数]){
初始化成员变量
}
成员方法
}
(2)类表达式
var 变量名=class{
构造函数([参数]){
初始化成员变量
}
成员方法
}
二、原型对象
1.构造函数的原型对象:通过prototype属性访问
2.对象的原型对象:通过对象的__proto__属性访问
3.访问对象的构造方法:在原型对象中有constructor属性指向对象的构造方法
(1)构造方法名.prototype.constructor
(2)对象名.constructor
function Person(){}
console.log(Person.prototype.constructor) //输出[function:Person]
var p1 = new Person()
console.log(p1.constructor) //输出[function:Person]
function Person(){} //原构造方法
var p2 = new Person()
console.log('p2:',p2.constructor) //输出[function:Person]
//给原型对象赋予一个新的对象
Person.prototype = { //原型对象的构造方法改变了
sayHello:function(){
console.log('Hello World')
}
}
var p1 = new Person() //调用新的构造方法实例化一个对象p1
console.log('p1:',p1.constructor) //输出[Function: Object]
4.原型对象的原型对象:原型对象本身也是一个对象,所有它也有一个原型对象
(1)获取原型对象的原型对象:构造方法名.prototype.__proto
(2)原型对象的原型对象构造方法:.prototype.__proto.constructor
ps:
A.JavaScript中的所有类都直接或间接的继承自object
B.所有的对象都是通过构造方法生成的
三、原型链的结构特点
1.构造函数和原型对象
构造函数------(prototype)------->原型对象
原型对象------(constructor)------->构造函数
2.实例对象和原型对象
实例对象------(__proto__)------>实例对象
构造方法------(new)------>实例对象
3.objec对象的__proto__属性是null
function Person(){
this.name = '张三'
}
Person.prototype.name = '李四'
var p = new Person()
console.log(p.name) //输出:张三
delete p.name //删除对象p的name成员
console.log(p.name) //在p对象的原型对象中查找name成员,输出:李四
delete Person.prototype.name //删除原型对象的name成员
console.log(p.name) //不存在,输出undefined
//给内置对象array的原型对象添加sum方法:用来求数组元素之和
Array.prototype.sum = function(){
let sum = 0
for(let i=0;i<this.length;i++){
sum += this[i]
}
return sum
}
//声明数组
var arr = [12,25,38,75]
console.log('数组元素之和:',arr.sum())
四、this指针的指向
1.构造函数内部的this指向新创建的对象(当前对象)
Function Person(){
this.name = ‘AA’
}
var p1 = new Person()\
var p2 = new Person()
2.直接通过函数名调用函数时,this指向全局对象window
function sayHello(){
return this
}
var t = sayHello()
3.若将函数作为对象的方法调用,this指向该对象
function Student(n,s){
this.name = n
this.sex = s
this.display = function(){
console.log(‘姓名:’+this.name+ ‘\n性别:’+this.sex)
}
}
var s1 = new Student(‘张飞’,‘男’)
s1.display() //通过对象名调用函数,此时
五、更改this指针的指向
1.apply方法
2.call方法
3.两个方法的区别
(1)在调用函数时,第一个参数默认是对象
(2)apply除第一个参数外,后面参数打包成数组进行传递
(3)call方法:除第一个参数外,后面的参数一个一个的传递
六、bind函数
实现提前绑定,在绑定时提前传入调用函数的参数
function method(a,b){
console.log(this.name+a+b)
}
var name = '张三'
var test = method.bind({name:'李四'},'3','4')
test()
七、JavaScript代码错误处理(异常处理)
1.try
try{
可能会出现错误的代码
}catch(e){ //e代表错误类型,名称可变
捕获到错误后的处理代码
}
var o = {}
try {
o.func() //出现错误:对象o没有func成员
console.log('AAAAA') //不执行,因为上一条语句错误
} catch (e) {
console.log(e) //执行:打印错误的类型及其详细信息
//TypeError是错误类型,o.func is not a function是错误信息
}
console.log('test') //执行:前一天语句的错误已经被try-catch捕获并处理了,不影响该语句的执行
2.throw抛出错误对象
try {
let e1 = new Error('错误信息') //创建错误对象,error是内置的错误类
throw e1 //抛出错误对象e1
} catch (error) { //catch捕获throw抛出的错误对象额e1,将e1赋给参数error
console.log(error.message) //输出错误对象的信息
}
3.常见的错误类型
(1)Error:普通错误。是其他错误对象的基类(其他对象错误都是继承Error)
(2)TypeError:变量或函数的参数出现类型错误
(3)SyntaxError:语法错误
(4)RangError:数值超出有效的范围
(5)URIError:解析URI编码出错
URI:统一资源标识符()
URL:全球资源定位器()
八、继承
1.ES6的继承:是单一继承(一个类的直接父类只能有一个)
class 子类名 extends 父类名
{
构造方法
成员方法
}
2.ES5的继承:通过原型对象实现(将父类的实例对象赋给子类的原型对象)
//通过原型链实现继承
//1.定义父类
function SuperType(){
this.property = '中国人民银行'
}
//2.给supertype的原型对象添加方法
SuperType.prototype.getSuperValue = function(){
return this.property
}
//3.定义子类构造方法
function SubType(){
this.subProperty = '中国工商银行'
}
//4.实现subtype对supertype的继承
SubType.prototype = new SuperType() //通过原型对象实现子类对父类的继承
//5.在子类的原型对象上增加一个方法
SubType.prototype.getSubValue = function(){
return this.subProperty
}
//6.创建一个子类的实例对象
let sub = new SubType()
console.log('调用父类的方法:',sub.getSuperValue()) //子类的实例对象用父类的方法
console.log('调用子类的方法:',sub.getSubValue())
3.在原型链继承中实现方法的覆盖(Override)
子类的方法名和父类的方法同名时,子类方法就覆盖了父类方法
实现方法:在子类的原型对象上添加和父类安全同名的方法
SubType.prototype.getSuperValue = function(){
return '中国建设银行'
}
4.在继承过程中确定原型对象和实例对象之间关系的方法
(1)instanceof运算符:判断实例对象的类型
console.log(sub instanceof Object) //true
console.log(sub instanceof SuperType) //true
console.log(sub instanceof SubType) //true
(2)isPrototypeOf()方法:判断原型对象的类型
console.log(Object.prototype.isPrototypeOf(sub)) //true
console.log(SuperType.prototype.isPrototypeOf(sub)) //true
console.log(SubType.prototype.isPrototypeOf(sub)) //true
5.原型链的问题
(1)若原型中包含引用值,则该引用值会在所有的实例对象中共享。这是属性放在构造方法中定义而不放在原型对象中定义的原因
function Father(){
this.colors = ['red','blue','green'] //colors属性的值是引用值(数组)
}
function Son(){}
//通过原型链的继承
Son.prototype = new Father() //本质:Son的原型对象是Father的实例对象
var s1 = new Son //创建子类的实例对象
s1.colors.push('black') //给属性colors添加已告知black
console.log('s1的colors:',s1.colors)
var s2 = new Son()
console.log('s2的colors:',s2.colors)
(2)子类的实例对象不能给父类的构造方法传参
6.原型链问题的解决办法
盗用父类构造方法(又称“对象伪造”或“经典继承”),基本思路是在子类构造方法中调用父类构造方法
(1)ES6中实现
class Father{ //父类
constructor(name){
this.name = name
}
show(){
console.log('姓名:',this.name)
}
}
class Son extends Father{ //子类
constructor(name){
super(name) //在子类构造方法中调用父类构造方法(经典继承,对象伪造)
}
}
(2)ES5中实现
function Father(name){
this.name = name
this.colors = ['red','blue','green']
this.show = function(){
console.log('姓名:',this.name)
}
}
function Son(subname){
Father.call(this,subname) //继承父类,在子类构造方法中通过call函数调用父类构造方法
}
let s1 = new Son('刘备')
s1.colors.push('black')
s1.show()
console.log(s1.colors) //输出:[ 'red', 'blue', 'green', 'black' ]
let s2 = new Son('诸葛亮')
s2.show()
console.log(s2.colors) //输出:[ 'red', 'blue', 'green' ]
九、类的实例化
使用new运算符创建实例对象的过程。在使用new运算符调用类的构造方法时会执行的操作
1.在内存中创建新对象:即给该对象分配一块存储区
2.在该新对象内部的[protptype]指针会指向构造函数的constructor属性
3.构造函数内部的this指针指向该新对象
4.执行构造函数内部的代码(给新对象添加属性和方法)
5.如果构造函数返回非空对象则返回该对象;否则返回刚创建的新对象