第三期:基于红皮书「建立js对象的6种方法」再讨论(1)

这一期所书写的目的并非为了介绍建立对象的方法,在红皮书里面,例子其实很清楚。在这篇文章中,想讨论一下书中细节,并无解释太清楚的地方。app

工厂模式

//工厂模式书本「
function createPerson(name,age){
    var obj=new Object();
    obj.name=name;
    obj.age=age;
    obj.load=function(){
        console.log(obj.name,obj.age);
    }
    return obj;
}

var toti=createPerson('toti',18);
toti.load();
//」工厂模式书本

工厂模式的一些要点:函数

  • 解决:优化

    • 建立多个类似对象问题this

    • 传参spa

  • 缺点:不能识别对象类型prototype

  • 优化:通常使用对象字面量写法,再返回code

  • 思考对象

    • 对象暴露出来,其实也能够用,可是赋值须要重复。ip

    • 包在一个函数里面,传参方便原型链

这个模式作了什么?

  1. 建立一个Object实例对象

  2. 为实例obj添加属性、方法

  3. 返回实例obj

至关于使用了一个普通的函数,去让这个对象能够复用。

书中:「不能识别对象类型」如何理解?

咱们的实例,当咱们去console.log(toti)的时候。可是工厂模式下,

clipboard.png

咱们去获取这个实例的时候,只能简单的判断它是一个对象。这就是它一个缺点,因而咱们有了后面的构造函数模式

使用对象字面量写法优化

//工厂模式对象字面量「
function createPerson(name,age){
    var obj={
        name:name,
        age:age,
        load:function(){
            console.log(this.name,this.age);
        }
    }
    return obj;
}

var mary=createPerson('mary',18);
mary.load();
//」工厂模式对象字面量

对象字面量注意问题

this的用法

  • 在obj对象里面,this.name&this.age指向obj的做用域的name&age

  • 若是不使用this,则name和age,指向createPerson的做用域。

  • 在本例中,使用this.name,name均可以,由于是传参,因此createPerson和obj两个做用域变量同样

构造函数模式

//「 构造函数模式;「 构造函数当作构造函数使用,用new
function Person(name,age){
    this.name=name;
    this.age=age;
    this.load=function(){
        console.log(this.name,this.age);
    }
}

var toti=new Person('toti',18);
toti.load();
console.log(typeof toti);
// 」构造函数模式;」构造函数当作构造函数使用,用new

发生了什么?

在解释发生的事情前,咱们要先详细了解下new的做用。在红皮书中,new的做用,解释的的确很浅,简单几行字,不细读,很难理清其中的逻辑。

NEW的做用

红皮书中是这样解释的:

  1. 建立一个新对象

  2. 将构造函数的做用域赋值给新对象

  3. 执行构造函数中的代码

  4. 返回新对象

这几行文字,一开始我也觉得我读懂了,可是它实在没有很好地给读者说明白new到底怎么用的。

在这里,我引用一个我提问中的网友的回答,下面是来自wei0613的回答:

function CO(){
    this.p = “I’m in constructed object”;
    this.alertP = function(){
        alert(this.p);
    }
}
var o2 = new CO();
var obj  ={};
obj.__proto__ = CO.prototype;
CO.call(obj);
return obj;

他用代码形式给咱们讲解了其中发生了什么事:

  1. new先建立了一个对象obj

  2. 而后CO函数的原型赋值给对象obj的原型

  3. CO函数再使用call/apply方法把做用域赋给obj

  4. 到这一步才执行构造函数Co里面的代码!!!

  5. 返回obj对象

你们可能第一眼,并不能发现我这里的逻辑和红皮书的逻辑有什么区别。首先,红皮书的逻辑中,很明显少了原型建立发生在哪一步,若是这里不清楚,会影响你们理解接下来原型模式和动态原型模式的理解;其次,第4步是最重要的,也就是构造函数的代码执行,是发生在第4步,call的使用和原型链的造成都发生在以前。若是咱们仅仅只有一个大概概念,当咱们遇到对象字面量重写的时候,咱们极可能发现咱们代码写得都没有问题,可是就是出bug的状况。这个工做流逻辑你们必定要清楚。

构造函数里this的做用

在new的时候,所谓的做用域赋给新对象,就是使用了call/apply方法。

  1. Person.apply(obj,arguments);

  2. this就指向了obj对象

  3. 把this的属性方法一个个添加到obj对象里面

其余不是this的属性和方法,都会被忽略,好比:

function Person(name, age,job){
    this.name=name;
    this.age=age;
    this.load=function(){
        console.log(this.name,this.age);
    }
    var job=job;
}

job就不会被写入obj对象里面

clipboard.png

注意,当咱们new Person()的时候,是把函数看成构造函数使用的,可是它也是函数,能够像普通函数同样使用

//「 构造函数当作普通函数使用,不用new
function Person(name,age){
    this.name=name;
    this.age=age;
    this.load=function(){
        console.log(this.name,this.age);
    }
}

var mike=Person('mike',18);
//mike.load();会报错,Person没有对象返回
window.load();
// 」构造函数当作普通函数使用,不用new

直接使用函数,等于在当前做用域下运行。在这种状况下,咱们则会把this指向这个环境的做用域,在这里是window。咱们使用mike.load()会报错,由于属性和方法并无添加到mike这个对象中,而是添加到了window这个对象。

若是咱们不用new,也能够实现this指向咱们想指向的对象

//「 构造函数当作普通函数使用,call,apply
function Person(name,age){
    this.name=name;
    this.age=age;
    this.load=function(){
        console.log(this.name,this.age);
    }
}

var obj={};
Person.call(obj,'mike',18);
obj.load();
// 」构造函数当作普通函数使用,call,apply

这些变式其实都是在充分了解new和this的用法后,天然写出来的。经过些变式,你们能够更好理解它们的用法。

相比工厂模式,构造函数模式的优缺点及思考

当咱们console.log(toti):

clipboard.png

咱们回顾工厂模式下,是:

clipboard.png

因此构造函数模式在这里比工厂模式更好,看到这里你们应该明白书中:「不能识别对象类型」的问题了。

构造函数模式要点

  • 解决:能够识别为一种特定的类型

  • 缺点:构造函数的每一个方法都被实例了一遍

  • 思考:

    • 构造函数开头大写,其余函数开头小写

    • 不使用new,至关于普通函数使用,this指向window,为window添加变量和方法

    • 也可使用call和apply来为第三方做用域添加

  • 重点:

    • new

    • this

相关文章
相关标签/搜索