Java教程

JavaScript面向对象(下)

本文主要是介绍JavaScript面向对象(下),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

JavaScript面向对象(下)

  • 1 构造函数
    • 1.1 构造函数
    • 1.2 静态成员和实例成员
    • 1.3 构造函数和类的区别
  • 2 原型
    • 2.1 原型对象
    • 2.2 访问对象的原型对象
    • 2.3 访问对象的构造函数
    • 2.4 原型对象的原型对象
    • 2.5 原型链
    • 2.6 函数在原型链中的结构
    • 2.7 成员查找机制
  • 3 this指向
    • 3.1 分析this指向
    • 3.2 更改this指向:call()和apply()
    • 3.3 bind()
  • 4 错误处理
    • 4.1 如何进行错误处理
    • 4.2 错误对象的传递
    • 4.3 抛出错误对象throw
    • 4.4 错误类型

1 构造函数

1.1 构造函数

构造函数:构造函数主要用来创建对象,并为对象的成员赋初始值。

示例:

function Person(name, age) {//定义一个函数,传入姓名和年龄参数
    this.name = name;//初始化对象
    this.age = age;
    this.sing = function () {
        console.log('我会唱歌');
    };
}
var p1 = new Person('张三', 18);//创建对象
var p2 = new Person('李四', 19);
console.log(p1.name); // 输出结果:张三
console.log(p2.age); // 输出结果:19
p2.sing(); // 输出结果:我会唱歌

结果为:
张三
19
我会唱歌

1.2 静态成员和实例成员

实例成员是指实例对象的成员,而静态成员是指通过类或构造函数访问的成员。

实例:静态属性

function Person(uname) {
    this.uname = uname;
}
Person.school = 'X大学'; // 添加静态属性school
Person.sayHello = function () {// 添加静态方法sayHello
    console.log('Hello');
};
console.log(Person.school);	// 访问静态属性,输出结果:X大学
Person.sayHello();	// 访问静态方法,输出结果:Hello

结果为:
X大学
Hello

1.3 构造函数和类的区别

区别:类中的成员方法是定义在类中的,使用类创建对象后,这些对象的方法都是引用了同一个方法,这样可以节省内存空间。

实例:方法共享

class Person {//定义一个Person类
    sing() {//定义唱歌方法
        console.log('hello');
    }
}
var p1 = new Person();//创建对象
var p2 = new Person();//创建对象
console.log(p1.sing === p2.sing);

输出结果:true

2 原型

2.1 原型对象

原型对象:每个构造函数(类)都有一个原型对象存在,这个原型对象通过构造函数的prototype属性来访问。

注意:
1、构造方法的原型对象是object类型
2、prototype属性是默认存在的
3、原型对象的作用:共享方法

示例:

function Person() { } // 定义函数
console.log(Person.prototype);//输出原型对象
console.log(typeof Person.prototype);//输出类型

结果是:
Person {}
object

通过原型对象增加方法:

构造方法名.prototype.添加的方法名 = function([参数]) {
    //方法体语句
}

【案例】利用原型对象共享方法。

function Person(uname) {//构造函数Person
    this.uname = uname;//初始化对象
}
Person.prototype.sayHello = function () {//给Person增加sayHello()方法
    console.log('你好,我叫' + this.uname);
};
var p1 = new Person('张三');//创建对象
var p2 = new Person('李四');
console.log(p1.sayHello === p2.sayHello); // 输出结果:true
p1.sayHello();// 输出结果:你好,我叫张三
p2.sayHello();// 输出结果:你好,我叫李四

2.2 访问对象的原型对象

对象的原型对象:每个对象都有一个默认的属性__proto__属性,该属性指向对象的原型对象

示例:

function Person() { }
var p1 = new Person();
console.log(p1.__proto__ === Person.prototype);

结果是:true

实例对象和原型对象:
1、实现对象:使用new运算符创建的对象
2、原型对象:①通过构造方法名(类名).prototype得到的对象;②通过对象的__proto__属性得到的对象

在这里插入图片描述

2.3 访问对象的构造函数

对象的构造函数:在原型对象里面有一个constructor属性,该属性指向了构造函数。

通过原型对象来访问构造方法,语法:

构造方法名(类名).prototype.constructor

通过实例对象访问构造方法

对象名.constructor

构造方法的作用:初始化对象


ES5通过原型对象访问构造方法:

//ES5
function Student(name, gender) {
    this.name = name;//this指向自己
    this.gender = gender;
}
var s1 = new Student("张三", "男");
var s2 = new Student("李四", "女");
console.log("原型对象访问构造方法:", Student.prototype.constructor);
console.log("原型对象访问构造方法:", Student.prototype.constructor === Student);

在这里插入图片描述
ES6通过原型对象访问构造方法:

//ES6  不能显式调用构造方法,只能通过类名调用方法
class Student {
    constructor(name, gender) {
        this.name = name;
        this.gender = gender;
    }
}
var s1 = new Student("张三", "男");
var s2 = new Student("李四", "女");
console.log("原型对象访问构造方法:", Student.prototype.constructor);

在这里插入图片描述


示例:

function Person() { }//定义一个构造函数
// 通过原型对象访问构造函数
console.log(Person.prototype.constructor === Person);// 输出结果:true
// 通过实例对象访问构造函数
var p1 = new Person();//不能显示调用构造方法,而是通过类名
console.log(p1.constructor === Person); // 输出结果:true

【案例】用赋值方式修改原型对象为新的对象,就无法访问构造函数。

function Person() { }
var p1 = new Person();
console.log("原来的原型对象:", Person.prototype);
console.log(p1.constructor)
// 修改原型对象为一个新的对象
Person.prototype = {
    sayHello: function () {
        console.log('hello');
    }
};
var p1 = new Person();
// 使用实例对象p1可以访问新的原型对象中的属性
p1.sayHello(); // 输出结果:hello
// 使用constructor属性无法访问原来的构造函数
console.log("修改后的原型对象:", p1.constructor);

在这里插入图片描述
构造函数、原型对象和实例对象之间的关系:
在这里插入图片描述

2.4 原型对象的原型对象

原型对象的原型对象:原型对象也是对象,那么这个对象应该也会有一个原型对象存在。

查看原型对象的原型对象的方法:

构造方法名/类名.prototype.__proto__

示例:

function Person() { }
// 查看原型对象的原型对象
console.log(Person.prototype.__proto__);
// 查看原型对象的原型对象的构造函数
console.log(Person.prototype.__proto__.constructor);

结果为:
{}
[Function: Object]

【案例】Person.prototype.__proto__这个对象其实就是Object.prototype对象。

function Person() { }
console.log(Person.prototype.__proto__ === Object.prototype); // true
var obj = {};
console.log(obj.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__); // 输出结果:null

结果为:
true
true
null

2.5 原型链

原型链结构的特点:
1、每个构造函数都有一个原型对象:通过prototype属性访问
2、原型对象通过constructor属性指回构造函数
3、实例对象通过__proto__属性指向原型对象
4、Object的原型对象的__proto__是null

原型链结构图:
在这里插入图片描述

2.6 函数在原型链中的结构

在这里插入图片描述

2.7 成员查找机制

1、先在对象中查找,JavaScript首先会判断实例对象有没有这个成员
2、若对象中没有,继续查找原型对象的原型对象
3、若仍没有找到,则返回undefined

示例:

function Person() {//构造Person函数
    this.name = "张三";//初始化
}
Person.prototype.name = "李四";//给构造函数的原型对象的name属性赋值为李四
var p = new Person();//创建对象
console.log("姓名:", p.name);//先在对象中查找,输出张三
delete p.name;//删除对象p的成员name
console.log("姓名:", p.name);//再从函数的原型对象中查找,输出李四
delete Person.prototype.name;//删除函数的原型对象中的name
console.log("姓名:", p.name);//再找原型对象的原型对象,输出undefined

在这里插入图片描述
【案例】利用原型对象扩展数组的方法——求数组元素之和

//Array:内置对象,下面扩展Array数组的方法
Array.prototype.sum = function () {//为Array的原型对象定义sum函数,求数组的和
    var sum = 0;//局部变量
    for (var i = 0; i < this.length; i++) {//this代表当前的对象
        sum += this[i];//将当前对象的每一项相加
    }
    return sum;//返回sum
}
var arr = [12, 32, 42, 50];
console.log("数组元素之和:", arr.sum());

数组元素之和: 136

3 this指向

3.1 分析this指向

函数中this指向,情况如下:
1、构造函数内部的this指向新创建的对象。
2、直接通过函数名调用函数时,this指向的是全局对象window。
3、如果将函数作为对象的方法调用,this将会指向该对象。

示例:

function foo() { //普通方法
    return this; //this指向全局的对象window
}
var o = {
    name: "橘猫吃不胖",
    func: foo
}
console.log(foo()) //foo函数的this指向全局对象window
console.log(foo() === window) //对应第2点,true
console.log(o.func())//对应第三点,将foo函数作为对象o的函数进行调用,此时,foo函数中的this指向o

在这里插入图片描述

3.2 更改this指向:call()和apply()

更改this指向方法有:apply()方法和call()方法。

apply()示例:

function method() {
    console.log(this.name); //this指向全局对象window
}
//更改了method方法中this的指向:此时this指向对象{name: '张三'}
method.apply({ name: '张三' });

结果为:张三

call()示例:

function method() {
    console.log(this.name); //this指向全局对象window
}
//更改了method方法中this的指向:此时this指向对象{name: '李四'}
method.call({ name: '李四' })

结果为:李四

apply()方法和call()方法的区别:
call()方法接受的是参数列表,而apply()方法接受的是一个参数数组。

apply()用法示例:

function method(a, b) {
    console.log(a + b);
}
method.apply({}, [1, 2]);//数组中是数字类型
method.apply({}, ["1", "2"]);//数组中是字符串类型

输出结果:
2
12

call()用法示例:

function method(a, b) {
    console.log(a + b);
}
method.call({}, 3, 4);//传入数字参数
method.call({}, "3", "4");//传入字符串参数

输出结果为:
7
34

3.3 bind()

bind()方法:实现提前绑定的效果。在绑定时,还可以提前传入调用函数时的参数。

示例:

function method(a, b) {
    console.log(this.name + a + b);
}
var name = "橘猫吃不胖"; //全局变量,属于window
//将{name:'小猫咪'}对象绑定到method上,此时,method方法中的this指向'小猫咪'
var test = method.bind({ name: "小猫咪" }, '3', '4');
method('1', '2'); //全局调用,函数中的this指向window
test();

在这里插入图片描述

4 错误处理

4.1 如何进行错误处理

使用try()…catch(),语法为:

try{
   //可能出现错误的代码
}
catch(e)
   //错误处理代码
}

catch:用来捕获错误,参数e用来捕获错误对象

错误案例演示:

var o = {};
o.func();// 这行代码会出错,因为调用了不存在的方法
console.log("test");// 前面的代码出错时,这行代码不会执行

在这里插入图片描述
当我们知道这行代码可能会出现问题时,就可以使用**try()…catch()**来进行错误处理,案例如下:

var o = {};
try {// 在try中编写可能出现错误的代码
    o.func();
    console.log("a");// 如果前面的代码出错,这行代码不会执行
} catch (e) {// 在catch中捕获错误,e表示错误对象
    console.log(e);
}
console.log('b'); // 如果错误已经被处理,这行代码会执行

在这里插入图片描述

4.2 错误对象的传递

书写错误代码:

function foo1() {
    foo2();//调用foo2函数
    console.log("foo1");
}
function foo2() {
    var o = {};
    o.func(); // 未定义这个函数,发生错误
}
foo1();

在这里插入图片描述
将上面的代码使用try()……catch()进行错误处理后:

function foo1() {
    foo2();//调用foo2函数
    console.log("foo1");
}
function foo2() {
    var o = {};
    o.func();//调用func()函数
}
try {
    foo1();//调用foo1函数
} catch (e) {
    console.log("test");//如果错误输出test
}

结果是:test

4.3 抛出错误对象throw

throw语句用来抛出一个用户自定义的异常。当前函数的执行将被停止(throw之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个catch块。如果调用者函数中没有catch块,程序将会终止。

try {
    var e1 = new Error("错误信息:橘猫吃胖了");
    throw e1; //将错误对象e1抛出
} catch (error) {
    console.log(error.message);//输出错误信息
    console.log(error === e1);//判断错误对象是否等于错误信息
}

在这里插入图片描述

4.4 错误类型

类型说明
Error表示普通错误,其余6种类型的错误对象都继承自该对象
EvalError调用eval()函数错误,已经弃用,为了向后兼容,低版本还可以使用
RangeError数值超出有效范围,如“new Array(-1)”
ReferenceError引用了一个不存在的变量,如“var a = 1; a + b;”(变量b未定义)
SyntaxError解析过程语法错误,如“{ ; }”“if()”“var a = new;”
TypeError变量或参数不是预期类型,如调用了不存在的函数或方法
URIError解析URI编码出错,调用encodeURI()、escape()等URI处理函数时出现
这篇关于JavaScript面向对象(下)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!