JS高级-构造函数与原型

JS高级-构造函数与原型,第1张

JS高级-构造函数与原型

文章目录 JS高级-构造函数与原型1.实例、静态成员以及构造函数1.1实例成员1.2静态成员1.3构造函数的问题 2.原型什么是原型?原型的作用是什么? 2.1构造函数原型 prototype2.2给原型对象添加属性(一般都是方法)2.3对象原型__proto__2.4 construct 构造函数2.5构造函数、实例、原型对象三者之间的关系 3.显示原型与隐式原型4.原型链5.JavaScript的成员查找机制(规则)6.原型对象的this指向问题7.扩展内置对象8.继承8.1 call()方法 8.2借用父构造函数继承属性8.3借用父构造函数继承方法

1.实例、静态成员以及构造函数 1.1实例成员 实例成员就是通过构造函数内部的this添加的成员实例成员只能通过实例化的对象来访问,不可以通过构造函数来访问实例成员
function Fun(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.test=function(){
        console.log('实例成员')
    }
}
var fun=new Fun('小阿涵',22,'男');
fun.test();
console.log(fun.name);
console.log(fun.test);

1.2静态成员 静态成员是指在构造函数本身上添加的成员静态成员只能通过构造函数来访问,不能通过对象来访问
function Fun(name,age,sex){
    this.name=name;
    this.age=age;
    this.sex=sex;
    this.test=function(){
        console.log('实例成员')
    }
}
var fun=new Fun('小阿涵',22,'男');
fun.test();
console.log(fun.name);
Fun.school='ZZGS';
console.log(Fun.school);

1.3构造函数的问题

构造函数虽然好用,但是存在内存浪费的问题

function Star(name,age){
    this.name=name;
    this.age=age;
    this.sing=function(){
        console.log('111')
    }
}
var ldh=new Star('GG',18)
var zxy=new Star('JJ',19)
上述代码中,sing()方法是一个函数,函数属于复杂数据类型,在我们的内存中,无论是ldh对象中还是zxy对象,该方法都会单独开辟出一个新的空间来存放该函数,因此便产生了内存浪费的问题我们可以通过prototype属性来改善上述问题
2.原型 什么是原型?

原型是一个对象,我们也称为prototype为原型对象

原型的作用是什么?

共享方法,节约内存资源

2.1构造函数原型 prototype 构造函数可以通过原型分配的函数是所有对象所共享的我们所创建的每一个函数,解析器都会向函数中添加一个prototype这个属性对应着一个对象,这个对象就是所谓的原型对象该对象的所有属性和方法,都会被构造函数所拥有如果函数作为普通函数调用prototype没有任何作用我们可以把那些不变的方法,直接定义到prototype对象上,这样所有对象的实例就可以共享这些方法 2.2给原型对象添加属性(一般都是方法)

一般情况下,我们的公共属性定义到构造函数里面,公共的方法我们放到原型对象上

function Star(name,age){
    this.name=name;
    this.age=age;
}
Star.prototype.sing=function(){
    console.log('原型方法')
}
var ldh=new Star('GG',18)
var zxy=new Star('JJ',19)
ldh.sing();

2.3对象原型__proto__

对象都会有一个__proto__指向构造函数的prototype原型对象,之所以我们对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在

function Star(name,age){
    this.name=name;
    this.age=age;
}
Star.prototype.sing=function(){
    console.log('原型方法')
}
var ldh=new Star('GG',18)
var zxy=new Star('JJ',19)
conslog.log(ldh);//对象身上系统自己添加一个 __proto__ 指向我们构造函数的原型对象

__proto__和prototype两个属性是等价的__proto__对象原型的意义就在于为对象的查找机制提供了一个方向,或者说一条路线,但是他是一个非标准属性
2.4 construct 构造函数

对象原型(proto)和构造函数(prototype)原型对象里面都有一个属性 constructor 我们称为构造函数,因为他指回构造函数本身

function Star(name,age){
    this.name=name;
    this.age=age;
}
Star.prototype.sing=function(){
    console.log('原型方法')
}
var ldh=new Star('GG',18)
var zxy=new Star('JJ',19)
conslog.log(ldh);

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SoKHQvYX-1652169794046)(img/11.png)]

2.5构造函数、实例、原型对象三者之间的关系

3.显示原型与隐式原型

(1)每个函数都有function都有一个prototype,即显示原型

function fun(){

}
console.log(fun.prototype);

(2)每个实例对象都有一个__proto__,可称为隐式原型

function Fun(){

}
console.log(Fun.prototype);
var fun=new Fun();
console.log(fun.__proto__)

(3)对象的隐式原型的值为其对应构造函数的显式原型的值

function Fun(){

}
console.log(Fun.prototype);
var fun=new Fun();
console.log(fun.__proto__)
console.log(Fun.prototype===fun.__proto__);//true

(4)总结:

函数的prototype属性:在定义函数时自动添加的,默认值是一个Object空对象对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值我们可以直接 *** 作显式原型,无法直接 *** 作隐式原型(ES6之前)prototype属性 与 __proto__属性 两者都为引用类型 4.原型链 只要是对象就有__proto__原型,指向我们的原型对象
function Star(name,age){
    this.name=name;
    this.age=age;
}
Star.prototype.sing=function(){
    console.log('我是Star原型对象的方法')
}
var ldh=new Star('ZZ',22);
console.log(Star.prototype);
console.log(Star.prototype.__proto===Object.prototype);
//Object.prototype原型对象里面的__proto__指向空
console.log(Object.prototype.__proto__);

因此我们的每一个对象实例都有一个__proto__原型,这个原型指向我们的原型对象prototype,这个原型对象里面也有一个__proto__,这个原型指向我们的Object的原型对象,Object原型对象里面的也有__proto__,但是这个__proto__指向空,这样的指向方向就构成了我们的原型链

5.JavaScript的成员查找机制(规则)

JavaScript的成员查找机制将遵循原型链的指向进行查找,一层一层逐步查找,同时遵循就近原则

(1)当访问一个对象的属性(包括方法)时,首先查找这个对象自身有没有这个属性(2)如果没有就差找他的原型(也就是__proto__指向的prototype原型对象)(3)如果还没有就查找原型对象的原型(Object的原型对象)(4)依次类推一直找到Object为止(null) 6.原型对象的this指向问题 (1)在构造函数里,里面的this指向的是我们的对象实例(2)原型对象函数里面的this指向的是 实例对象
function Star(name,age){
    this.name=name;
    this.age=age;
}
var that;
Star.prototype.sing=function(){
    console.log('我是Star原型对象的方法');
    that=this;
}
var ldh=new Star('ZZ',22);
ldh.sing();
console.loh(that===ldh);//true

因此不管是构造函数里面的this还是原型对象里面的this都指向我们的实例对象

7.扩展内置对象

可以通过原型对象,对原来的内置对象进行自定义的方法,比如给数组增加自定义求偶数和的功能

Array.prototype.sum=function(){
    var num=0;
    for(var i=0;i<this.length;i++){
        num+=this[i];
    }
    return num;
}
var arr=[1,2,3];
console.log(arr.sum());
console.log(Array.prototype);

8.继承

ES6之前没有给我们提供extends继承,我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承

8.1 call()方法

调用这个函数,并且修改函数运行时的this指向
语法:函数名.call(thisArg,arg1,arg2…)
thisArg:当前调用函数this的指向对象

function fun(){
    console.log('zz');
    console.log(this);
}
var a={
    name:'zh'
}
fun.acll();//this ===> window
fun.call(a);//this ===> a
8.2借用父构造函数继承属性

我们通常将共有的属性写到构造函数里面

//父构造函数
function Father(name,age){
    this.name=name;
    this.age=age;
}
//子构造函数
//通过call方法修改子构造函数的this指向
function Son(name,age){
    Father.call(this,name,age);
}
var son=new Son('zz',22);
console.log(son);

8.3借用父构造函数继承方法

我们通常将共有的方法写到原型对象上

//父构造函数
function Father(name,age){
    this.name=name;
    this.age=age;
}
Father.prototype.money=function(){
    console.log('父方法');    
}
//子构造函数
//通过call方法修改子构造函数的this指向
function Son(name,age){
    Father.call(this,name,age);
}
//让Son的原型等于Father的实例对象
Son.prototype=new Father();
//因为上述代码我们修改了原型对象,因此需要利用constructor来指向原来的原型对象
Son.prototype.constructor=Son;
//单独给子类添加一个方法
Son.prototype.exam=function(){
    console.log('考试')
}
var son=new Son('zz',22);
console.log(son);
console.log(Father.prototype);
console.log(Son.prototype.constructor);

因此可以根据原型链的指向方式来更好理解上述代码

欢迎分享,转载请注明来源:内存溢出

原文地址: http://www.outofmemory.cn/web/941134.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-17
下一篇 2022-05-17

发表评论

登录后才能评论

评论列表(0条)

保存