ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

JavaScript面向对象(下)

2021-11-24 21:00:30  阅读:99  来源: 互联网

标签:console log Person 对象 JavaScript 面向对象 原型 构造函数


JavaScript面向对象(下)

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处理函数时出现

标签:console,log,Person,对象,JavaScript,面向对象,原型,构造函数
来源: https://blog.csdn.net/m0_46612221/article/details/121480662

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有