JS 创建对象的三种方式

原文转载自:https://blog.csdn.net/qq_29712603/article/details/51789832

 

 __proto__属性在js中是相当重要的概念,面向对象编程和委托设计都是围绕它展开的。但同时它在js的内部实现中,却十分的复杂,这里我们好好讨论下这个独特的属性。
            首先这个属性是什么?在官方的es5中,定义了一个名叫[[prototype]]的属性,每个对象都拥有这样一个属性,这个属性是一个指针,它指向一个名叫原型对象的内存堆。而原型对象也是对象,因此又含有自己的[[prototype]]的属性,又指向下一个原型对象。那么终点是哪? 当然是我们的Object.prototype对象。
           也就是说,js中的对象模型大概是这个样子:


          
       注意,这里使用的是[[prototype]],而并非__proto__。那么这是一个东西吗?当然![[prototype]]是官方所定义的属性,而__proto__是浏览器自己对[[prototype]]所做的实现。也就是说,官方并未定义[[prototype]]叫什么,是浏览器自己根据标准制定出来的。但是!在ES6官方把[[prototype]]作为对象的内部属性,跟[[configurable]]一样,外部无法直接访问。现在已经定义了专门访问该内部属性的函数,有兴趣大家可以看看:点击打开链接。
       不过上面的图,有点问题。当对象刚刚被创建时,它的内部并非如此。实际上它的内部状态分好几种情况:
使用字面量定义一个对象时: var foo={};
创建一个函数对象时:function Foo();
使用构造函数定义一个对象时: var  foo=new Foo();
       以上是最基本的三个状态,其他的状态都是由这三个状态变化而成的。
       1 先来看第一个情况: var foo={};
       此时会生成一个新的对象,而由于没有对他的[[prototype]]进行任何的操作,所以默认情况下所指向的是Object.prototype对象:
    var  foo={};
    foo.__proto__===Object.prototype;//true
    Object.prototype.toString.call(foo.__proto__);//该方法返回对象类型的字符串:object Object 
    foo.hasOwnProperty('__proto__');//false
       

       但是,让我们来看下代码的最后一行,执行的结果却是false。也就是__proto__并非在普通对象的内部,它其实是在Object.prototype上。而 foo.__proto__可以正常运行,是因为引擎调用了getter函数,大家可以试下执行:alert(foo.__proto__),你会看到输出结果为:function(){} ,意思为这个指针所访问的内容是个空函数。这个里面比较复杂,有兴趣的可以去看看:深入js这本书。但是一般情况下,我们可以简单的理解为访问__proto__时,就是在访问Object.prototype,如果你没把__proto__指向其他对象的话。
       2 接下来看看比较复杂的第二张情况:function Foo();
       我们知道,Foo函数也是一个对象,当然他也可以访问__proto__内部属性。但是他的__proto__的内部属性并非跟普通对象一样指向Object.prototype对象,相反他指向Function.prototype对象,而Function.prototyp对象的__proto__再指向Object.prototype。
     
    function foo(){};
    Object.prototype.toString.call(foo.__proto__);//object  Function
    foo.__proto__===Function.prototype;//ture
   Object.prototype.toString.call(foo.__proto__.__proto__);//object  Object   
    foo.__proto__.__proto__.===Object.prototype;//ture


              
     我们知道,每个Js函数对象,都拥有一个原型对象,这个原型对象是函数自己的属性,并且这个原型对象跟普通对象没有区别,因此它也可以访问__proto__,自然它的__proto__指向的是Object.prototype了。
    function foo(){};
    alert(foo.hasOwnProperty('prototype'));//ture  prototype为foo的自身属性
    alert(foo.propertyIsEnumerable('prototype'));//false  prototype不可枚举
    foo.prototype.__proto__===Object.prototype;// 原型对象访问__proto__属性,指向Object.prototype
     也就是说。原型对象是在函数对象下的一个属性,而普通对象是没有原型对象。这就为接下来的用new 调用函数进行面向对象编程打下了基础。
     结合起来,当我们定义一个函数时,内部同时产生了 __proto__和prototype属性:


      
      3 最后来看看最复杂的: var foo=new Foo{};
       对于new操作,一般来讲是四步操作:1 生成一个新对象  2 将新对象执行原型链接到函数的prototype对象上,3 把新对象绑定到this上, 4 如果没有return,返回函数执行结果的新对象。
      这里的关键点在于第二步操作。很多人将其解释为,new的新对象是函数自身的prototype对象,其实根本不是如此。通过上面的第二点的代码,我们就已经知道了函数原型对象一开始就便存在,只是它是不可枚举的空对象而已。而且,有个重点:函数原型对象没有在原型链中!也就是说引擎进行右值查询时,根本不会理会函数原型对象!
     
  function foo(){};
  foo.prototype.y=10;
  alert(foo.y);//    undefined
  foo.__proto__.x=10;
  alert(foo.x);//    10
    从上面的我们就可以看出,对函数对象进行原型链查询,是不会检索函数原型对象的。
     那么new所创建的是个什么对象呢? 我们知道在函数作用域里所定义的变脸,外部环境是访问不到的。这样的话,如何把内部所生成好的变量传递给外部变量呢?最主要的方式是使用return .而另一个情况:在c++这些语言中,则是创建一个匿名对象,由匿名对象保存函数所生成的数据,然后当它把数据传递给外表环境时,自身就会释放内存消失掉。
     js中正是使用的后一个方法:它创建一个匿名的对象,负责保存所有的数据,同时在没有return情况下,当对象把数据传递给外表环境后就释放内存:
   
  function Foo(){this.a=a;};
  var test=new Foo(10);

   上面代码的内部情况为:


    
    当Foo函数执行完成后,匿名对象消失,所有的数据都被保存到了test上。此时,test的__proto__就指向了之前的函数原型对象了,而不再是Object.prototype.
--------------------- 
作者:飞翔的侠客 
来源:CSDN 
原文:https://blog.csdn.net/qq_29712603/article/details/51789832 
版权声明:本文为博主原创文章,转载请附上博文链接!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: JavaScript创建对象的几种方式包括: 1. 对象字面量:使用花括号{}创建一个对象,可以在其中定义属性和方法。 2. 构造函数:使用关键字new和一个函数来创建一个对象,可以在函数中定义属性和方法。 3. Object.create()方法:使用一个现有的对象作为原型来创建一个新的对象,可以在新对象中添加或修改属性和方法。 4. 工厂函数:使用一个函数来创建对象,该函数返回一个新的对象,可以在函数中定义属性和方法。 5. ES6中的类:使用class关键字来定义一个类,可以在类中定义属性和方法,使用new关键字来创建一个对象。 ### 回答2: JavaScript是一门面向对象的脚本语言,因此创建对象在其中是非常重要和基础的一环。 JavaScript创建对象方式可以分为以下几种: 1. Object构造函数 Object是JavaScript中的内建构造函数,它可以创建一个对象或者通过传递参数创建具有属性的对象。 例子: ``` var obj = new Object(); //创建一个对象 var car = new Object(); //创建有属性的对象 car.brand = "BMW"; car.color = "blue"; ``` 2. 对象字面量 对象字面量是一种简便的创建对象方式,它可以直接将属性与属性值的对应关系写在一起,通过花括号{}进行标识。 例子: ``` var obj = {}; //创建一个对象 var car = { //创建有属性的对象 brand: "BMW", color: "blue" }; ``` 3. 构造函数 可以使用函数作为模板来创建对象,这样的函数就被称为构造函数。通过使用new关键字去实例化这个函数创建一个对象。 例子: ``` function Car(brand, color) { //定义构造函数 this.brand = brand; this.color = color; } var myCar = new Car("BMW", "blue"); //实例化构造函数,创建对象 ``` 4. 原型 JavaScript的原型实现了面向对象的继承机制,对象继承其原型的属性和方法。因此可以通过原型来创建对象。 例子: ``` function Car() { //定义构造函数 } Car.prototype.brand = "BMW"; //在原型上定义属性 var myCar = new Car(); //实例化构造函数,创建对象 console.log(myCar.brand); //输出"BMW" ``` 以上是JavaScript中创建对象的几种方式,它们各自具有优点和适用范围。我们可以根据自己的实际需要,选择最适合的方式创建对象。 ### 回答3: JavaScript创建对象方式有多种,常用的有: 1.字面量方式:使用对象字面量创建对象 var person = { name: "John", age: 20, gender: "male", sayHello: function() { console.log("Hello, my name is " + this.name); } }; 2.构造函数方式:使用构造函数创建对象 function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; this.sayHello = function() { console.log("Hello, my name is " + this.name); } } var person = new Person("John", 20, "male"); 3.原型方式:使用原型创建对象 function Person() {} Person.prototype.name = "John"; Person.prototype.age = 20; Person.prototype.gender = "male"; Person.prototype.sayHello = function() { console.log("Hello, my name is " + this.name); } var person = new Person(); 4.简单工厂方式:通过一个工厂函数创建对象 function createPerson(name, age, gender) { var person = {}; person.name = name; person.age = age; person.gender = gender; person.sayHello = function() { console.log("Hello, my name is " + this.name); } return person; } var person = createPerson("John", 20, "male"); 5.构造函数和原型组合方式:使用构造函数和原型结合创建对象 function Person(name, age, gender) { this.name = name; this.age = age; this.gender = gender; } Person.prototype = { constructor: Person, sayHello: function() { console.log("Hello, my name is " + this.name); } }; var person = new Person("John", 20, "male"); 以上是JavaScript创建对象的常见方式,不同的方式都有各自的优缺点,选择合适的方式可以提高执行效率和开发体验。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值