深度解析new原理及模拟实现

此文借鉴于此,并在此文基础上进行学习

一、定义

new运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例

function Car(color) {
    this.color = color
}

Car.prototype.start = function() {
    console.log(this.color + "car start");
}

var car = new Car("black")
console.log(car.color);//black    访问构造函数中的属性

car.start();//blackcar start    访问原型中的属性

以上代码可以看出new创建的实例有以下两个特性

1、访问到构造函数里的属性
2、访问到原型链中的属性

二、注意点

ES6新增Symbol类型,不可以使用new Symbol(),因为symbol是基本的数据类型,每个从Symbol()返回的symbol值都是唯一的

Number("123"); // 123
String(123); // "123"
Boolean(123); // true
Symbol(123); // Symbol(123)

new Number("123"); // Number {123}
new String(123); // String {"123"}
new Boolean(true); // Boolean {true}
new Symbol(123); // Symbol is not a constructor

三、模拟实现

(1)new操作符会进行如下操作

a、创建一个空的简单的JavaScript对象 
b、为步骤a新创建的对象添加属性__proto__,将该属性链接至构造函数的原型对象
c、将步骤a新创建的对象作为this的上下文
d、如果该函数没有返回对象,则返回this

(2)以new Foo()执行时为例子,再次分析

a、一个继承自Foo.prototype的新对象被创建
b、使用指定的参数调用构造函数Foo,并将this绑定到新创建的对象上。new Foo等同于 new Foo(),也就是没有指定参数列表,Foo不带任何参数调用的情况
c、由构造函数返回的对象就是 new 表达式的结果。如果构造函数没有显式的返回一个对象,则使用步骤1创建的对象

(3)版本one

new 是关键词,不可以直接覆盖。这里使用create来模拟实现new的效果

new 返回一个新对象,通过obj.__proto__ = Con.prototype继承构造函数的原型,同时通过Con.apply(obj,arguments)调用构造函数实现继承,获取构造函数上的属性

function create() {
    
    //创建一个新对象
    var obj = new Object()
    //获得构造函数,arguments中去除一个参数
    let Con = [].shift.call(arguments)
    //链接到原型,obj可以访问到构造函数原型中的属性
    obj.__proto__ = Con.prototype
    //绑定this实现继承,obj可以访问到构造函数中的属性
    Con.apply(obj,arguments); //把Con的this用obj来代替
    //返回对象
    return obj
}


function Car(color) {
    this.color = color
}

Car.prototype.start = function() {
    console.log(this.color + "car start");
}

var car = create(Car,"black")
car.color
car.start()//blackcar start

(4)版本two

解决上述构造函数返回值的问题

构造函数的返回值有如下三种情况:

a、返回一个对象
b、没有return,即返回undefuned
c、返回undefined以外的基本类型

a、返回一个对象: 实例中的car只能访问到返回对象中的属性

function Car(color,name) {
    this.color = color

    return {
        name : name
    }
}

var car = new Car("black","BNM")
console.log(car.color);//undefined
console.log(car.name);//BNM

b、没有return,即返回undefined: 实例中的car只能访问到构造函数中的属性,与情况a刚好相反

function Car(color,name) {
    this.color = color
}

var car = new Car("black","BMN")

console.log(car.color);//black
console.log(car.name);//undefined

c、返回undefined以为的基本类型: 实例car中只能访问到构造函数中的属性,和情况a刚好相反,结果相当于没有返回值

function Car(color,name) {
        this.color = color
        return 1
    }
    
var car = new Car("black","BMN")
    
console.log(car.color);//black
console.log(car.name);//undefined

结合以上,我们第二版需要判断返回值是不是一个对象,如果是对象返回这个对象,不然返回新创建的obj对象

function create() {
    //创建一个空的对象
    var obj = new Object()
    //将构造函数返回出来,并将新对象的__proto__链到构造函数的原型对象上
    var Con = [].shift.call(arguments)
    obj.__proto__ = Con.prototype
    //绑定this实现继承,obj可以访问到构造函数中的属性
    var ret = Con.apply(obj,arguments)
    //优先返回构造函数返回的对象
    return ret instanceof Object ? ret : obj
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++多态是面向对象编程中一个非常重要的特性,它能够让我们在编写代码时更加灵活,同时也提高了代码的可维护性和可扩展性。多态的实现原理主要是通过虚函数和指针实现的。 在C++中,我们可以通过将父类中的函数声明为虚函数来实现多态。一个类中如果有虚函数,那么就会生成一个虚函数表(vtable),这个表中存储着虚函数的地址。在编译时,编译器会为每个对象分配一个指向虚函数表的指针(vptr),这个指针会被存储在对象的内存布局中。 当我们通过一个父类的指针或引用来调用一个虚函数时,实际上会根据对象的类型来查找对应的虚函数表,然后再根据虚函数表中的函数地址来调用实际的函数。这个过程被称为动态绑定(dynamic binding),这样就能够实现多态了。 以下是一个简单的示例: ```C++ class Animal { public: virtual void speak() { cout << "I am an animal" << endl; } }; class Dog : public Animal { public: void speak() { cout << "I am a dog" << endl; } }; Animal* animal = new Animal(); Animal* dog = new Dog(); animal->speak(); // 输出 I am an animal dog->speak(); // 输出 I am a dog ``` 在上面的示例中,Animal和Dog都有一个speak()函数,其中Animal的speak()函数是虚函数。当我们通过Animal指针调用speak()函数时,会调用Animal的speak()函数;当我们通过Dog指针调用speak()函数时,会调用Dog的speak()函数。这就是多态的实现过程。 总的来说,C++的多态能够通过虚函数和指针来实现,它能够让我们在编写代码时更加灵活,同时也提高了代码的可维护性和可扩展性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值