Javascript原型,原型链,面向对象

本文深入探讨JavaScript中prototype和__proto__的区别与联系,解析构造函数模式与原型模式结合使用的方法,以及动态构造和寄生构造模式等面向对象编程技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

prototype

function才会有的属性

__proto__

所有对象都有的属性,但不是标准属性,是部分浏览器提供的

一般可以认为:

__proto__ === constructor.prototype
不过也有例外,如果修改了prototype的指向,此等式就不成立了。

function Foo(){
    this.name='Tom';
}

var obj = {};
console.log(obj.__proto__);//{}
console.log(obj.__proto__ === obj.constructor.prototype) //true


var fo = new Foo();
console.log(fo.__proto__); //Foo{}
console.log(fo.__proto__ === fo.constructor.prototype); //true


var foo = Object.create(fo);
console.log(foo.__proto__); //Foo{}
console.log(foo.__proto__ === foo.constructor.prototype); //false


因为:Object.create() 会把prototype重新赋值
Object.create = function(o){
    var F = Function(){};
    F.prototype = o;
    return new F();
}

此时 foo.constructor.prototype === fo.__proto__


原型模型:
Function.prototype = {
      constructor : Function
     ,__proto__ : parent prototype
    [,other prototypes : ....]
}

原型所带来的问题

虽然原型对面向对象的实现带了来便利,但是与此同时也带来了缺点:

  • 没有了构造函数传递初始化的过程,这个在某种程度上带来了一些不便
  • 最大的问题是引用的特性,带来了数据共享的问题
function Person(){}

Person.prototype = {
  constructor : Person,
  name : 'tom',
  age : 10,
  hobbies : ['book','gril']
}

let person1 = new Person();
let person2 = new Person();

person1.hobbies.push('boy');

console.log(person1.hobbies); // 'book','gril','boy'
console.log(person2.hobbies); // 'book','gril','boy'
### 解决办法:使用构造函数模式
  1. 构造函数模式和原型模式混用

    function Person(name,age){
     this.name = name;
     this.age = age;
     this.hobbies = ['book','gril']
    }
    
    Person.prototype = {
     constructor : Person,
     sayName : () => {
       console.log(this.name);
     }
    }
    
    let person1 = new Person('tom',10);
    let person2 = new Person('jim',11);
    
    person1.hobbies.push('boy');
    
    console.log(person1.hobbies); //['book','gril','boy']
    console.log(person2.hobbies); //['book','gril']
    
    console.log(person1.sayName === person2.sayName); // true

  2. 动态构造模式

    function Person(name, age){
     this.name = name;
     this.age = age;
    
     if(typeof this.sayName != 'function'){
       Person.prototype.sayName = () =>{
         console.log(this.name);
       };
     }
    }
    
    let person = new Person('tom', 1);
    person.sayName();//tom

    只有在sayName不存在的情况下构造实例时才会初始化到原型中,且初始化完成后会立即体现在所有实例中。

  3. 寄生构造模式

    function Person(name, age, hobbies){
       let t = new Object();
       t.name = name;
       t.age = age;
       t.hobbies = hobbies;
       t.sayName = function() {
         console.log(this.name);
       };
       return t;
     }
    
     let person1 = new Person('tom', 10,['a','b']);
     let person2 = new Person('jim',11,['a','b','c']);
     person1.sayName(); //'tom'
     person2.sayName(); //'jim;
     console.log(person1.hobbies); //[ 'a', 'b' ]
     console.log(person2.hobbies); //[ 'a', 'b', 'c' ]

    细心的同学会发现,这种模式和工场模式一模一样。

  4. 稳妥构造函数模式

    function Person(name, age) {
       var t = {};
       t.sayName = () => {
           console.log(name);
       };
       return t;
    }
    
    let person = new Person('tom', 11);
    person.sayName(); //'tom'

    此种模式下只能通过sayName才能访问到name属性。

    稳妥模式的思想就是不引入this,这在一些不能用this的场景中很有必要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值