当前位置:网站首页>js创建对象,构造函数,this,原型,继承

js创建对象,构造函数,this,原型,继承

2022-08-11 11:51:00 -加油

js创建对象

1、使用构造函数

使用函数声明式创建函数对象
(各实例间互不影响,是两个不同的实例)

function Fun(){
    
    this.name = ['林北星','张万森','展宇'];
    this.age = ['17','17','19'];
    this.fun = function(){
    
        console.log('这是对象的方法');
    }
}
console.log(Fun);
var s1 = new Fun();//创建实例对象
var s2 = new Fun()
// 这两个是不同的实例 是不同的Fun对象
console.log(s1);
console.log(s2);
s1.name.push('hhhh');//修改s1不会影响s2
console.log(s1);
console.log(s2);
s1.fun();//使用属性方法

或者
使用函数表达式赋值式创建函数对象
同样(各实例间互不影响,是两个不同的实例)

let Fun=function(){
    
    this.name = ['林北星','张万森','展宇'],
    this.age = ['17','17','19'],
    this.fun = function(){
    
        console.log('这是对象的方法');
    }
}
console.log(Fun);
var s1 = new Fun();//创建实例对象
var s2 = new Fun()
// 这两个是不同的实例 是不同的Fun对象
console.log(s1);
console.log(s2);
s1.name.push('hhhh');//修改s1不会影响s2
console.log(s1);
console.log(s2);
s1.fun();//使用属性方法

或者
(各实例间影响,因为传的同一个数组——引用类型)
引用传递

function Fun(name,age){
    
    this.name = name;
    this.age = age;
    this.fun = function(){
    
        console.log('这是对象的方法');
    }
}
let names = ['林北星','张万森','展宇'];
let ages = ['17','17','19'];
// 数组是对象,数组names,ages都是引用传递的
var s1 = new Fun(names,ages);//创建实例对象
var s2 = new Fun(names,ages);//创建实例对象
console.log(s1);
console.log(s2);
console.log(s1.name);// 数组 [ '林北星', '张万森', '展宇' ]
console.log(s1.name===s2.name);// true
console.log(s1.age===s2.age);// true
s1.name.push('hhhh');//修改s1同时修改了s2
console.log(s1);
console.log(s2);
s1.fun();//使用属性方法

或者
不影响 传的不是同一个,是两个不同的实例。

 function Fun(name,age){
    
    this.name = name;
    this.age = age;
    this.fun = function(){
    
        console.log('这是对象的方法');
    }
}
let name1 = ['林北星','张万森','展宇'];
let age1 = ['17','17','19'];
let name2 = ['庄文杰','罗坚','大智'];
let age2 = ['17','17','19'];
var s1 = new Fun(name1,age1);//创建实例对象
var s2 = new Fun(name2,age2);//创建实例对象
console.log(s1);
console.log(s2);
s1.name.push('hhhh');//修改s1不会修改s2
console.log(s1);
console.log(s2);
s1.fun();//使用属性方法

2、Object

let s = new Object();
s.name = ['林北星','张万森','展宇'];
s.age = ['17','17','19'];
s.fun = function(){
    
    console.log('这是对象的方法');
}
console.log(s);
s.fun();

或者:

let s = new Object({
    
    name:['林北星','张万森','展宇'],
    age:['17','17','19'],
    fun(){
    
        console.log('这是对象的方法');
    }
    // 也可以这么写:
    // fun:function(){
    
    // console.log('这是对象的方法');
    // }
})
console.log(s);
s.fun();

或者

let s = {
    
    name:['林北星','张万森','展宇'],
    age:['17','17','19'],
    fun(){
    
        console.log('这是对象的方法');
    }
     // 也可以这么写:
    // fun:function(){
    
    // console.log('这是对象的方法');
    // }
}
console.log(s);
s.fun();

或者
Object.create
两个实例相互影响

let s1 = {
    
    name:['林北星','张万森','展宇'],
    age:['17','17','19'],
    fun(){
    
        console.log('这是对象的方法');
    }
    // 也可以这么写:
    // fun:function(){
    
    // console.log('这是对象的方法');
    // }
}
console.log(s1);
let s2 = Object.create(s1)
console.log(s2);
s2.name.push('hhhh');//修改s1 也会影响s2
console.log(s1);
console.log(s2);
s1.fun();

3.原型

在这里插入图片描述
构造函数与实例

function Fun(){
    
    this.name = ['林北星','张万森','展宇'];//私有 不共享
    this.age = ['17','17','19'];
    this.fun = function(){
    
        console.log('这是对象的方法');
    }
}
let s = new Fun();
//实例与构造函数
console.log(s.__proto__==Fun.prototype);//true

构造函数与原型对象
Fun.prototype .constructor===Fun
每个函数都有prototype属性,它的结构:

Fun.prototype = {
    
    constructor: Fun,
    ......其他原型属性和方法
}

原型对象作用:为每个实例对象存储共享的方法和属性。
所有的实例共享同一个原型对象。
实例有很多份,实例属性和方法是独立的。
在构造函数中,为属性的私有性,方法的复用共享性,一般将属性封装在构造函数中,将方法定义在原型对象上。

4.继承

原型链继承
parent一般将属性封装在构造函数中,将方法定义在原型对象上。
new Parent
优点:共享原型对象上的方法,方法定义在父类原型上,复用父类构造函数方法,如say方法。
缺点:
子实例会共享父类构造函数的引用属性。比如下例子的arr属性。
无法实现多继承。
不能向父类传参。


function Parent(name,age){
    
    //属性封装在构造函数中
    this.name = name;
    this.age = age;
    this.arr = [1];
}
//方法定义在原型对象上
Parent.prototype.say = function(){
    
    console.log('hhhhhhh');
}
function Child(like){
    
    this.like = like;
}
//原型链继承
Child.prototype = new Parent('庄文杰','19');//此时Child.prototype.constructor == Parent
Child.prototype.constructor = Child;
let s1 = new Child('sing');//这个传参,不能传到父类构造函数
let s2 = new Child('dance');//这个传参,不能传到父类构造函数
s1.say();//输出hhhhhhh
s2.say();//输出hhhhhhh
console.log(s1.say===s2.say);//true 复用,是共享的
console.log(s1.name);
console.log(s2.name);
console.log(s1.arr);
console.log(s2.arr);
s1.arr.push(2);//修改s1的arr,s2也会影响
s1.name = '罗队';//修改s1的name,不会影响s2
console.log(s1.arr);
console.log(s2.arr);
console.log(s1.name);
console.log(s2.name);

用构造函数继承
使用call 改变this指向
new Child
优:可向父类构造函数传参,不共享引用属性。
缺:方法不能复用,独立的。
不能继承父类原型上的方法。

function Parent(name){
    
    this.name = name;
    this.arr = [1];
    this.say = function(){
    
        console.log('hhhhhhhhhh');
    }
}
Parent.prototype.fun = function(){
    
    console.log('pppppp');
}
function Child(name,like){
    
    Parent.call(this,name);//把this指向Child,拷贝了父的实例属性和方法
    this.like = like;
}
let s1 = new Child('庄文杰','sing');//向父类传参
let s2 = new Child('罗队','dance');
console.log(s1.name);
console.log(s2.name);
console.log(s1.arr);
console.log(s2.arr);
s1.arr.push(2);//修改s1的arr 不会影响到s2
console.log(s1.arr);
console.log(s2.arr);
console.log(s1.say===s2.say);//false 独立的
s1.fun();//报错 fun is not a function
s2.fun();//不能继承父类原型上的方法

组合继承
原型链继承+构造函数继承

function Parent(name){
    
    //属性封装在构造函数中
    this.name = name;
    this.arr = [1];
}
//方法定义在原型对象上
Parent.prototype.say = function(){
    
    console.log('hhhhhhh');
}
function Child(name,like){
    
    Parent.call(this,name)
    this.like = like;
}
Child.prototype = new Parent();//此时Child.prototype.constructor == Parent
Child.prototype.constructor = Child;
let s1 = new Child('庄文杰','sing');//这个传参,不能传到父类构造函数
let s2 = new Child('罗队','dance');//这个传参,不能传到父类构造函数
s1.say();//输出hhhhhhh
s2.say();//输出hhhhhhh
console.log(s1.say===s2.say);//true 复用,是共享的
console.log(s1.name);
console.log(s2.name);
console.log(s1.arr);
console.log(s2.arr);
s1.arr.push(2);//修改s1的arr,不会影响s2 没共享
s1.name = '大智';//修改s1的name,不会影响s2
console.log(s1.arr);
console.log(s2.arr);
console.log(s1.name);
console.log(s2.name);

由于调用两次父类构造方法, Parent.call(this,name)和new Parent(),会存在一份多余的父类实例属性。
优化:
改成
原型式继承+构造函数

Child.prototype = Parent.prototype;

还是有缺点:当修复子类构造函数的指向后:
Child.prototype.constructor = Child;
父类实例的构造函数指向也会跟着变。
再优化:
改成
寄生组合继承:

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

ES6 extends继承

class Parent{
    
    constructor(){
    
        this.age = 18;
    }
}
//子Child 继承父 Parent super 必须在子的this.xxx = xxx前面
//子没有自己的this,它是继承父的this,所以需要先super获得this
class Child extends Parent{
    
    constructor(){
    
        // this.name = '庄文杰'; 会报错 super()必须在前面
        super();//因为Child没有this指向,这句必须要有
        this.name = '庄文杰';    
    }
}
let obj = new Child();
// console.log(obj.age);//18
console.log(obj.name);//庄文杰

继承super含参数

class Parent{
    
    constructor(age,sex){
    
        this.age = age;
        this.sex = sex
        this.dd = '我是爹地'
        this.tv = '重生之门'
    }
    say(){
    
        console.log('扮演'+this.boy);
    }
    hi(){
    
        console.log('这部剧叫'+this.tv);
    }
    father(){
    
        return this.dd
    }
}
class Child extends Parent{
    
    constructor(name,_age,_sex){
    
        super(_age,_sex);
        this.name = name;    
        this.boy = '庄文杰';
        this.dd = '庄耀柏'  
        // this.tv = '重生' 有它则是它
    }
    son(){
    
        //注意father中的this
        console.log(super.father()+'的儿砸');
    }
}
let obj = new Child('王俊凯','18','男');
console.log(obj.age);//18
console.log(obj.name);//王俊凯
obj.say();//扮演庄文杰
obj.hi();//这部剧叫重生之门 注意这里的tv
obj.son();//庄耀柏的儿砸 注意这里的dd

super:

//this指向函数所在的当前 对象
//super 指向当前对象的 原型对象
var obj1 = {
    
    fun1(){
    
        console.log('obj1的fun1');
    }
}
var obj2 = {
    
    fun2(){
    
        //使用super前提:将obj2的原型加到obj1上
        super.fun1();//实际上是调用obj2.prototype.fun1()
    }
}
//将obj2的原型加到obj1上
Object.setPrototypeOf(obj2,obj1)
obj2.fun2();//obj1的fun1
//this指向函数所在的当前 对象
//super 指向当前对象的 原型对象
var obj1 = {
    
    name:'obj1',
    fun1(){
    
        return this.name
    }
}
var obj2 = {
    
    name:'obj2',
    fun2(){
    
        //使用super前提:将obj2的原型加到obj1上
        console.log(super.name);//obj1
        console.log(this.name);//obj2
        return super.fun1()
    }
}
//将obj2的原型加到obj1上
Object.setPrototypeOf(obj2,obj1)
//super 虽然指向原型对象的fun1方法,但是this指向还是绑定当前obj2对象
console.log(obj2.fun2());//obj2
原网站

版权声明
本文为[-加油]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_51040174/article/details/124981358