一、继承Ⅱ
- 混入式继承
- 原型式继承
- 原型链继承
- 借用构造函数继承
- 组合继承
1.1-原型链继承的实现
实现原理:将子类的原型对象指向父类的实例对象。
实现方法:子类.prototype = new 父类()
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function () {
console.log("name:",this.name,"age:",this.age);
}
function Student(score) {
this.score = score;
}
Student.prototype = new Person("小明",10);//继承父构造函数并设置name和age的值
Student.prototype.getScore = function () {
console.log("分数:"+this.score);
}
var p1 = new Student(100);
p1.name="xxx"//只能这样一个个修改,无法向父类传参
var p2 = new Student(12);
console.log(p1);
console.log(p2);
存在问题:存在数据共享问题,无法给父类构造函数传递参数
1.2-借用构造函数继承的实现
1.2.1-call方法和apply方法的基本使用
定义:将方法借给某个对象的方法。call和apply作用相同,写法不同。
使用call方法的语法:
被借用对象.方法.call(借用对象)
使用apply方法的语法:
被借用对象.方法.apply(借用对象)
特点:可以设置方法中this的指向——方法中的this指向借用对象
var obj1 = {
name:"Neld",
age:10,
showInfo:function () {
console.log("name:"+this.name,"age:"+this.age);
}
}
var obj2 = {
name:"Lily",
age:12
}
obj1.showInfo();//name:Neld age:10
obj2.showInfo();//obj2.showInfo is not a function
obj1.showInfo.call(obj2);//name:Lily age:12
// obj1.showInfo.apply(obj2);//name:Lily age:12
call和apply的区别(传参方式不同) :
// call传参,跟在借用对象后面,用逗号隔开
被借用对象.方法.call(借用对象,参数1,参数2……)
// apply传参,不能直接写在后面,要将参数封装在数组中跟在借用对象后面,用逗号隔开
被借用对象.方法.apply(借用对象,[ 参数1,参数2…… ])
需求:给obj1添加add方法,需要传入两个参数,完成加法运算。然后将这个方法借给obj2对象,通过obj2传入参数,完成加法运算
var obj1 = {
name:"Neld",
age:10,
add : function (a, b) {
return a + b;
}
}
var obj2 = {
name:"Lily",
age:12
}
//使用cal方法
obj1.add.call(obj2, 100, 200);
//使用apply方法
//console.log(obj1.add.apply(obj2, 1, 2));//CreateListFromArrayLike called on non-object
obj1.add.apply(obj2, [100, 200]);
1.2.2借用构造函数继承说明
实现原理:在子构造函数中调用父构造函数,达到继承并向父构造函数传参的目的。
实现方法:
- 将父对象的构造函数设置为子对象的成员
- 调用这个方法,类似于将父构造函数中的代码复制到子构造函数中来执行
- 用完之后删掉
function Person(name,age) {
this.name = name;
this.age = age;
}
Person.prototype.getInfo = function () {
console.log("name:",this.name,"age:",this.age);
}
function Student(name,age,score) {
this.newMethod = Person;//1.将父对象的构造函数设置为子对象的成员
this.newMethod(name, age);//2.调用这个方法,类似于将父构造函数中的代码复制到子构造函数中来执行
this.score = score;
delete this.newMethod;//3.用完之后删掉
}
Student.prototype.getScore = function () {
console.log("分数:"+this.score);
}
var p1 = new Student("Neld", 10 ,100);
var p2 = new Student("Lily", 12 ,80);
console.log(p1);
console.log(p2);
高级实现方法:凡是要借用方法,首先想到使用call或apply
function Student(name,age,score) {
//Person.call(this,name,age);
Person.apply(this,[name,age]);
this.score = score;
}
这种继承方式都存在下面两个问题:
- 如果父子构造函数存在相同的成员,那么子构造函数会覆盖父构造函数中的成员
- 不能继承原型链中的成员
1.3-组合继承的基本结构
实现原理:基原型链继承+借用构造函数继承
function Student(name,age,score) {
//Person.call(this,name,age);
Person.apply(this,[name,age]);//继承构造函数中的成员
this.score = score;
}
Student.prototype = new Person();//继承原型链上的成员
Student.prototype.constructor = Student
总结: ECMAScript 实现继承的方式不止一种。这是因为 JavaScript 中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适用的继承方式。
二、绘制完整的原型链结构图
这一节重点探讨函数对象的原型链结构。完整的结构图如下:
总结:
- 所有的函数对象都是Function类型,由Function构造函数创建
- Function的原型对象是一个匿名空函数,绑定了函数中的通用方法
- 空函数对象的类型是Object
- Function函数对象由自身的构造函数创建
三、基本包装类型的使用
3.1-基本包装类型的创建
定义:方便对string,number,boolean三种基本类型数据操作,ECMAScript提供了三个特殊引用类型——基本包装类型(String,Number,Boolean)
创建方式:
// 方式一:
var str1 = new String("string1");
var num1 = new Number(123);
var bool1 = new Boolean(true);
console.log(str1);
console.log(num1);
console.log(bool1);
// 方式二
var str2 = new Object("string2");
var num2 = new Object(456);
var bool2 = new Object(false);
console.log(str2);
console.log(num2);
console.log(bool2);
基本类型和基本包装类型的比较
var str1 = "test";
var str2 = new String("test");
var str3 = "test2";
var str4 = new String("test");
console.log(str1 == str2);//①
console.log(str1 == str3);//②
console.log(str2 == str4);//③
console.log(str1 === str2);//④
console.log(str1 === str3);//⑤
console.log(str2 === str4);//⑥
①:字符串的基本类型和包装类型比较,默认会调用包装类型的toString方法,把转换的结果再进行比较
str1 == str2.toString(),这样得到的结果是相等的,返回true
②:两个基本类型比较,值不等,返回false
③:两个包转类型比较的是地址,地址不同,返回false
④:===比较类型和值,这里是类型不同,返回false
⑤:两者值不同,返回false
⑥:两者类型相同但是引用地址不同,返回false
另外两种类型和字符串类型一样的讨论点,这里就不再一一列举。
3.2-基本包装类型使用的注意点
先看下面的代码,观察存在的问题:
var str = "test";
console.log(str.length);//4
console.log(str.substr(0, 2));//te
上面代码看似很简单,但是存在一个很基本的疑问点:
str是基本类型,不存在属性和方法一说,但是下面两行代码中却是在访问属性和方法,而且代码还能正确的执行,这是如何实现的呢?
其实,为了让我们实现这种直观的操作,后台已经自动完成了以下操作:
- 创建 String 类型的一个实例;
- 在实例上调用指定的方法;
- 销毁这个实例;
var str = "test";
var obj = new String(str);
console.log(obj.length);
console.log(obj.substr(0, 2));
obj = null;//使用完之后销毁obj
经过此番处理,基本的字符串值就变得跟对象一样了。而且,上面这三个步骤也分别适用于 Boolean和 Number 类型对应的布尔值和数字值
3.3-Number类型扩展注意点
在Number包装类型的使用过程中还有下面这些点是需要我们注意的。
Number.prototype.add = function (num) {
return this + num;
}
var num = 100;
var ret = num.add(100);//①
console.log(ret);//200
在程序执行的时候,num直接指向一个Number对象,所以可以直接访问到Number中的add方法,那么我们可以直接使用num对应的数字来访问add方法吗?也就是 100.add(100) ;
这种写法在JS语法中这样的代码是不能通过的。但是可以稍加修改就可以了,我们只需用 () 将数字括起来即可:
console.log((100).add(100));//200
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!