javascript对象创建方式-对象之间的继承

文章详细介绍了JavaScript中创建对象的多种方式,包括字面量、newObject()、工厂模式、构造函数、构造函数+原型链以及ES6的class。同时,文章讨论了对象间的继承,如原型链继承、构造函数继承、组合继承等,并分析了各种继承方式的优缺点。最后,提到了new关键字的工作原理。
摘要由CSDN通过智能技术生成
一、对象创建的几种方式:字面量创建、new Object()、构造函数、构造函数+原型链、class方式

1,字面量创建对象

var obj= {name:'CSDN',age:10}

2,使用new Object()方法创建

var obj = new Object({name:'feel',type:2})

3,工厂模式(封装、特点:能够批量生产)

function dog(type,gender){
   let obj ={type , gender} 
   //或者 let obj1 = new Object({type , gender} )
   return  obj
}
let dog1 = dog("哈士奇","公")
let dog2 = dog("柯基","母")
console.log(dog1,dog2); 
//{type: '哈士奇', gender: '公'} {type: '柯基', gender: '母'}

4,构造函数(javascript定义的方法)

// 自定义构造函数 首字母大写
function Preson(name, age, gender) {
         this.name = name
         this.age = age
         this.gender = gender
        }
 
 // 创建对象的时候必须使用new
let p1 = new Preson("小黑", 10, "男")

创建实例的时候 ,必须用new关键字。(new关键字创建的时候过程在结尾)

5,构造函数+原型链,这种比较完善

function Person(name,age){
        this.name = name
        this.age = age
        this.setAge =function(){
            console.log('age',this.age);
        }
        this.testArr = [1,2,3]
      }
//Person.prototype.testArr = [1,2,3]
Person.prototype.setName = function(name){  //在自定义构造函数的原型对象中添加方法
        console.log(this.name);
      }

let obj1 = new Person("小明",12,'画画')
let obj2 = new Person("小李",13,'画画1')

大家可以打印一下obj1.setName == obj2.setName的结果值

以及obj1.setAge == obj2.setAge的结果值,他们之间的区别,

以及第七行的数组如果放在第9行的Person的原型上,随便一个实例修改的时候,其他实例这个数组的值。可以自行打印一下。

结果:

两个实例,创建完成时具有Person身上的属性和方法,也就是有name,age,setAge这些,两个实例创建完成后在内存空间开辟两个问题,分别放obj1和obj2,他们有各自的steAge方法,但是,Person.prototype原型上面的setName方法,并没有创建到实例本身上,所以实例本身是没有这个方法的。通过原型链的知识,可以知道,实例本身没有这个方法,会向上一层,一层一层的寻找,直到最后。所以实例往上寻找,到Person的原型上,找到这个方法。意思就是实例调用的不是自身的方法,而是构造函数原型上的方法。

如果,我们把第七行注释,把第九行放开,使用一个实例向数组push内容。打印看

实例2身上的属性也发生了改变。所以,有引用属性的时候,必须把引用属性放在构造函数本身,不能放在原型上。

6,class模式(代码结构清晰)、constructor 放实例成员

定义方法前加 static为静态方法 里面的this指向构造函数

直接定义的为原型对象里面的方法 this指向实例

class Person {
    // 构造函数
    constructor(name, age) {
        // 实例成员
        this.name = name
        this.age = age
    }
    // 原型成员 (在其prototype对象里)
    eat() {
      // this 指向式实例
        console.log(this.name + "爱睡觉");
    }
    // 静态成员
    static shows() {
        // 静态成员this指向构造函数Person    
        console.log(this.name + "爱吃饭");
    }
    }
    // 实例化
    var p = new Person("小白", 10)
    console.log(p);  // Person {name: '小白', age: 10}
    p.eat()  // 小白爱睡觉
    Person.shows() //Person爱吃饭

//静态成员只能通过构造函数调用 static方法,就是可以创建变量的标识,只能自己用,实例用不了。

二、对象之间的继承

js中对象之间的继承有7种方式:原型链继承、构造函数继承、组合继承、原型式继承、寄生继承、寄生组合式继承、以及ES6中的class中的继承

1,原型链继承

function Animal(){
    this.name = 'animal'
}
Animal.prototype.getAnimalName = function (){
    console.log(this.name + 'getAnimalName');
}
//子类
function Cat(){
    this.name = 'cat'
}
// Cat继承Animal,将Animal的实例对象赋值给Cat的原型对象,
Cat.prototype = new Animal()
Cat.prototype.getCatName = function (){
    console.log(this.name + 'getCatName');
}

console.log(Cat.prototype.__proto__ === Animal.prototype);//true
// 给Cat的原型对象上声明一个方法

// 在使用原型链继承的时候,要在继承之后再去原型对象上定义自己所需要的属性和方法,因为在继承之前在原型对象上定义方法和属性将会被覆盖
// 创建实例对象cat1
var cat1 = new Cat()
console.log(cat1);//{name:'cat'}
// 调用自己原型对象上定义的方法
cat1.getCatName()//catgetCatName
// 调用继承Animal原型对象上的方法
cat1.getAnimalName()//catgetAnimalName

特点:

  • 让新实例的原型等于父类的实例

缺点:

  • 新实例无法向父类构造函数传参。

  • 继承单一

2,构造函数继承

使用 .call(this)方法将父类构造函数引入子类函数

//父类
function Person(name, age) {
            // 父类身上的属性 和 方法
            this.name = name
            this.age = age
            this.play = [1, 2, 3]    //引用类型
            this.setName = function () {
              console.log(name)
            }
        }
//子类
function Student(name, age) {
            Person.call(this, 'jimi',12)//相当于this.Person(name,age)
                      this.name = name
            this.setScore = function () {}
        }

                var s1 = new Student('Tom', 20)
        console.log(s1) 
 // Student {name: 'Tom', age: 12, play: Array(3), setName: ƒ, setScore: ƒ}

特点:

  • 实现多个构造函数属性的继承(call多个)

  • 实现子类向父类传参

缺点:

  • 只能继承父类实例上的属性和方法,不能继承原型上的属性和方法

  • 每个实例都有父类构造函数的副本,臃肿

3,组合继承

是原型继承和构造函数继承两种的结合

function Person(name, age) {
            // 父类身上的属性 和 方法
            this.name = name
            this.age = age
            this.play = [1, 2, 3]
            this.setName = function () {}
        }
        // 父类原型链上的方法
        Person.prototype.setAge = function () {
            console.log('111');
        }
//子类
function Student(name, age, price) {
            Person.call(this, name, age)//相当于this.Person(name,age)    构造函数模式
            this.price = price
            this.setScore = function () {}
        }

        Student.prototype = new Person()    //原型链模式
        Student.prototype.constructor = Student()    //原型对象私有化//因为此时子类的构造函数指
//向不对
        Student.prototype.sayHello = function () { }
                var s1 = new Student('Tom', 20, 15000)
                 var s2 = new Student('Jack', 22, 14000)
        console.log(s1,s2)

优点:

  • 可以继承实例属性/方法,也可以继承原型属性/方法

  • 不存在引用属性共享问题

  • 可传参

  • 函数可复用

缺点:

  • 调用了两次父类构造函数,生成了两份实例

4,原型式继承

使用Object.create()方法

//父类
function Person(name, age) {
            // 父类身上的属性 和 方法
            this.name = name
            this.age = age
        }
var testPer = new Person();
let Student = Object.create(testPer)
//console.log(Student)    //Person{}

//相当于:
//封装一个容器,输入对象和承载继承的原型
function content(Obj){
  function F(){}    
  F.prototype = Obj    继承传入的参数
  return new F()    //返回函数对象
}
//用法:
var test = new Person()    //用他的实例,当做那个函数的参数,返回一个对象
var Student = content(test)
//console.log(Student)    
//这里的打印和上面的那个打印效果是一样的。

特点:

  • 封装一个函数,返回一个对象

缺点:

  • 无法传递参数

  • 多个实例的引用类型属性指向相同的内存,存在篡改的可能

5,寄生式继承

在原型上的基础上增强Object.create()的方法,最后返回一个对象

        function createA(original) {
            var clone = Object.create(original) //调用函数,创建一个对象
            clone.sayHello = function () { //增强对象
                console.log('hello');
            }
            return clone; //返回对象
        }
        // 使用:
        var person12 = {
            name: 'mashang',
        }
        var per = createA(person12)
        console.log(per);//F{sayHello:f()}
        per.sayHello();//hello

//相当于:
function content(obj){    //原型式继承
  function F(){}
  F.prototype = obj
  return new F()
}
var Stu1 = new Person();
//继续套壳子,传递参数
function subObject(obj){
  var sub = content(obj)    
  sub.name = 'tom'
  return sub
}
var Stu2 = subObject(Stu1);//    传的参数,使用的函数,
//函数声明后,就成了可增添属性的对象
//console.log(typeof subObject)        //function
//console.log(typeof Stu2)    //object
//console.log(Stu2.name)    //'tom',继承的sub属性

特点:

  • 给原型式继承外面套了个壳子,可以增添一些方法

缺点:

  • 没用到原型,无法实现复用,

6,寄生组合式继承

是将组合式和寄生式结合起来,是目前最成熟方法

//父类
function Person(name, age) {
            // 父类身上的属性 和 方法
            this.name = name
            this.age = age
            this.play = [1, 2, 3]
            this.setName = function () {}
        }
        // 父类原型链上的方法
        PersonN.prototype.setAge = function () {
            console.log('111');
        }
//子类
function Student(name, age, price) {
            Person.call(this, name, age)//相当于this.Person(name,age)
            this.price = price
            this.setScore = function () {}
        }

        Student.prototype = Object.create(Person.prototype)
        Student.prototype.constructor = Student//修复构造函数指向的
                var s1 = new Student('Tom', 20, 15000)
                 var s2 = new Student('Jack', 22, 14000)
        console.log(s1,s2)
        

特点:

  • 减少构造函数,减少性能开销

7,class实现继承

class Parent {
            //    构造函数
            constructor(name) {
                this.name = name
            }
            // 原型方法
            // 即 Person.prototype.getName = function() { }
            getName() {
                console.log("Person", this.name);
            }
        }

 //子类
        class ChildClass extends Parent {
            //自身的 构造函数
            constructor(name, age) {
                //在子类的构造函数中   首先调用super()函数,继承父类属性方法
                super(name)
                this.age = age
            }
            getAge() {
                console.log('Child', this.age);
            }
        }

const dog = new ChildClass('dog', 1)
dog.getAge()    //Child 1
dog.getName() //调用父类方法  Person dog 

特点

  • ES6非常完善的继承方法

结尾:

  • new关键字过程

例:let obj = new Object()

1,开辟一个内存空间,创建一个空对象

2,将实例的__proto__对象指向Object构造函数的prototype属性上

3,改变this指向从指向构造函数改变为指向改新对象

4,给实例添加属性方法

最后,返回这个继承而来的对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值