javascript构造函数及原型对象

/*
* @ javascript中没有类的概念,所以基在对象创建方面与面向对象语言有所不同
* @ 对象创建的常用方法及各自的局限性
* @ 使用Object或对象字面量创建对象
* @ 工厂模式创建对象
* @ 构造函数模式创建对象
* @ 原型模式创建对象
* @ 构造与原型混合模式创建对象
*/

使用Object或对象字面量创建对象

/*
* @ 使用Object或对象字面量创建对象
* @ 最基本的创建对象的方法
*/
// 创建一个student对象, new一个Object
var student = new Object();
student.name = "easy";
student.age = "20";
// 如果嫌这种方法麻烦, 有种封装不良的感觉,试试字面量创建

对象字面量方式来创建对象

/*
* @ 对象字面量方式来创建对象
* @ 缺点,无法重复
*/
var student = {
    name: "easy",
    age: "20"
}

// 当我们要创建同类的student1, student2,...,studentN时, 不得不将以上的代码重复N次
var student2 = {
    name: "easy2",
    age: "20"
}
// ...
var studentn = {
    name: "easyn",
    age: "20"
}
// 这样麻烦而且重复太多, 能不能像工厂间那样, 有一个车床不断生产出对象.

工厂模式创建对象

/*
* @ 工厂模式创建对象
* @ JS中没有类的概念, 那么我们不妨就使用一种函数将以上对象创建过程封装起来以便于重复调用
* @ 同时可以给出特定接口来初始化对象
*/
function createStudent(name, age){
    var obj = new Object();
    obj.name = name;
    obj.age = age;
    return obj;
}

var student1 = createStudent("easy1", 20);
var student2 = createStudent("easy2", 20);
// ...
var studentn = createStudent("easyn", 20);

// 这样就可以通过createStudent函数源源不断地"生产"对象了, 看起来很完美了,但我们不仅希望"产品"的生产可以像工厂间一样源源不断,还想知道生产的产品究竟是哪一种类型

// 比如说: 我们同时又定义了"生产"水果对象的createFruit()函数
function createFruit(name, color){
    var obj = new Object();
    obj.name = name;
    obj.color = color;
    return obj;
}

var v1 = createStudent("easy1", 20);
var v2 = createFruit("apple", "green");

console.log(v1 instanceof createStudent);   // false
console.log(v2 instanceof createFruit);     // false
console.log(v1 instanceof Object);          // true
console.log(v2 instanceof Object);          // true
// 如果我们用instanceof操作符去检测, 他们统统都是Object类型

// 我们希望v1是student类型, 而v2是fruit类型, 那我们可以用构造函数来创建对象

/*
* @ "构造函数" 和 "普通函数" 有什么区别
* @ 一.实际上并不存在创建构造函数的特殊语法, 构造函数就是一个普通函数, 与普通函数唯一的区别在于调用方法
* @ 二.对于任意函数,使用new操作符调用, 那么它就是构造函数; 不使用new操作符调用, 那么它就是普通函数
* @ 三.按照惯例,我们约定构造函数名以大写字母开头
* @ 四.使用new操作符调用构造函数时,会经历4个阶段
*   @ 1.创建一个新对象
*   @ 2.将构造函数作用赋给新对象(使用tihs指向该新对象)
*   @ 3.执行构造函数代码
*   @ 4.返回新对象
*/

构造函数模式创建对象

// 将工厂模式函数重写, 并添加一个方法属性
function Student(name, age){
    this.name = name;
    this.age = age;
    this.alertName = function(){
        alert(this.name);
    }
}

function Fruit(name, color){
    this.name = name;
    this.color = color;
    this.alertName = function(){
        alert(this.name);
    }
}

// 分别new出Student和Fruit的对象
var v1 = new Student("easy", 20);
var v2 = new Fruit("apple", "green");

// 这样就可以用instanceof操作符来检测以上对象类型区分出不同的对象
console.log(v1 instanceof Student);        // true
console.log(v2 instanceof Student);        // false
console.log(v1 instanceof Fruit);          // false
console.log(v2 instanceof Fruit);          // true
console.log(v1 instanceof Object);         // true
console.log(v2 instanceof Object);         // true

// 这样解决了工厂模式无法区分对象类型, 但这样就完美了吗, 在JS中,函数是对象, 当我们实例化不只一个Strudent对象的时候

var v1 = new Student("easy1", 20);
var v2 = new Student("easy2", 20);
//...
var vn = new Student("easyn", 20);
// 其中共同的alertName()函数也被实例化了n次, 我们可以用以下方法来检测不同的Strudent对象并不共用alertName()函数
console.log(v1.alertName == v2.alertName);      // false

// 这无疑是一种内存的浪费,我们知道this对象是在运行时基于函数的执行环境进行绑定. 在全局函数中,this对象等同于window, 在对象方法中,this指向该对象

// 试将对象方法移到构造函数外部
function Student(name, age){
    this.name = name;
    this.age = age;
    this.alertName = alertName;
}
function alertName(){
    alert(this.name);
}
var stu1 = new Student("easy1", 20);
var stu2 = new Student("easy2", 20);

// 在调用"stu1.alert()时", this对象才被绑定到stu1上, 通过alertName()函数定义为全局函数, 这样对象中的alertName属性则被设置为指向该全局的指针, 由此stu1和stu2共享了该全局函数, 解决了内在浪费的问题

// 但是,通过全局函数的方式解决对象内部共享的问题, 终究不像一个好的解决方法, 更好的方案是通过原型对象模式来解决

原型模式创建对象

/*
* 原型模式创建对象
* @ 函数的原型对象
* @ 对象实例和原型对象的关联
* @ 使用原型模型创建对象
* @ 原型模型创建对象的局限性
*/

/*
* 函数的原型对象
* @ 每一个函数都有一个prototype属性, 该属性是一个指针,该指针指向了一个对象
* @ 创建的构造函数, 该对象中包含可以由所有实例共享的属性和方法
* @ 在默认情况下,所有原型对象会自动包含一个constructor属性, 该属性也是一个指针, 指向prototype所在的函数
*/

/*
* 对象实例和原型对象的关联
* @ 在调用构造函数创建新的实例时, 该实例的内部会自动包含一个[[Prototype]]属性, 该指针指向构造函数的原型对象, 指针关联的是"实例与构造函数的原型对象" 而不是"实例与构造函数"
*/

使用原型模型创建对象

/*
* 使用原型模型创建对象
* @ 直接在原型对象中添加属性和方法
*/
function Student(){

}

Student.prototype.name = "easy";
Student.prototype.age = 20;
Student.prototype.alertName = function(){
    alert(this.name);
}

var stu1 = new Student();
var stu2 = new Student();
// true 二者共享同一个函数
console.log(stu1.alertName == stu2.alertName);

// 我们在Strudent的prototype对象添加了name, age属性以及alertName方法, 但创建的stu1和stu2中并不包含name, age属性以及alertName()方法, 只包含一个[[prototype]]指针属性, 当我们调用stu1.name或stu1.alertName时, 是如何找到对应的属性和方法的呢?

// 当我们需要读取对象的某个属性时, 都会执行一次搜索,首先在该对象中查找该属性, 若找到,返回该属性, 否则, 到[[prototype]] 指向的原型对象中继续查找

// 看出另一层意思是: 如果对象实例中包含和原型对象中同名的属性或方法, 则对象实例中的该同名属性或方法会屏蔽原型对象中的同名属性或方法, 原因就是"首先在该对象中查找该属性, 若找到,返回该属性值"

通过对象字面量重写原型对象

function Student(){}

Student.prototype = {
    constructor: Student,
    name: "easy",
    age: 20,
    alertName: function(){
        alert(this.name);
    }
}
// 要特别注意,我们这里相当于用对象字面量重新创建了一个Object对象,然后使Student的prototype指针指向该对象。该对象在创建的过程中,自动获得了新的constructor属性,该属性指向Object的构造函数。因此,我们在以上代码中,增加了constructor : Student使其重新指回Student构造函数。

// 原型模型创建对象的局限性
// 原型模型在对象实例共享数据方面给我们带来了很大的便利, 但通常情况下不同的实例会希望拥有属性自己的单独的属性, 我们将构造函数的模型和原型模型结合使用即可兼得数据共享和"不共享"

构造与原型混合模式创建对象

/*
* 构造与原型混合模式创建对象
* 我们结合原型模式在共享方法属性以及构造函数模式在实例方法属性方面的优势,使用以下的方法创建对象
* 在构造函数中定义实例属性,在原型中定义共享属性的模式,是目前使用最广泛的方式。通常情况下,我们都会默认使用这种方式来定义引用类型变量。
*/

// 我们希望每个stu拥有属于自己的name和age属性
function Student(name, age){
    this.name = name;
    this.age = age;
}

// 所有的stu应该共享一个alertName()方法
Student.prototype = {
    constructor: Student,
    alertName: function(){
        alert(this.name);
    }
}

var stu1 = new Student("Jim", 20);
var stu2 = new Student("Tom", 21);

stu1.alertName();
stu2.alertName();

alert(stu1.alertName == stu2.alertName);  //true  共享函数
时间: 2024-08-07 21:17:51

javascript构造函数及原型对象的相关文章

深入javascript——构造函数和原型对象

深入javascript——构造函数和原型对象 常用的几种对象创建模式 使用new关键字创建 最基础的对象创建方式,无非就是和其他多数语言一样说的一样:没对象,你new一个呀! var gf = new Object(); gf.name = "tangwei"; gf.bar = "c++"; gf.sayWhat = function() { console.log(this.name + "said:love you forever");

链接:深入理解javascript构造函数和原型对象

链接:深入理解javascript构造函数和原型对象http://www.jb51.net/article/55539.htm

Javascript构造函数、原型对象、实例的关系与区别

构造函数与普通函数的唯一区别,就在于调用方式.任何函数通过new形式调用,就都是构造函数. 原型对象,只要创建了一个函数,那么一定会为这个函数创建一个prototype属性.而这个属性指向的就是原型对象. 实例,是new构造函数之后的结果.它会包含一个[[prototype]]属性(该属性无法直接访问),该属性指向原型对象. function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 2

谈谈对Javascript构造函数和原型对象的理解

对象,是javascript中非常重要的一个梗,是否能透彻的理解它直接关系到你对整个javascript体系的基础理解,说白了,javascript就是一群对象在搅..(哔!). 常用的几种对象创建模式 使用new关键字创建最基础的对象创建方式,无非就是和其他多数语言一样说的一样:没对象,你new一个呀! var gf = new Object(); gf.name = "tangwei"; gf.bar = "c++"; gf.sayWhat = function

javascript面向对象系列第一篇——构造函数和原型对象

× 目录 [1]构造函数 [2]原型对象 [3]总结 前面的话 一般地,javascript使用构造函数和原型对象来进行面向对象编程,它们的表现与其他面向对象编程语言中的类相似又不同.本文将详细介绍如何用构造函数和原型对象来创建对象 构造函数 构造函数是用new创建对象时调用的函数,与普通唯一的区别是构造函数名应该首字母大写 function Person(){ this.age = 30; } var person1 = new Person(); console.log(person1.ag

javascript面向对象——构造函数和原型对象

一般地,javascript使用构造函数和原型对象来进行面向对象编程,它们的表现与其他面向对象编程语言中的类相似又不同.本文将详细介绍如何用构造函数和原型对象来创建对象 构造函数 构造函数是用new创建对象时调用的函数,与普通唯一的区别是构造函数名应该首字母大写 function Person(){ this.age = 30; } var person1 = new Person(); console.log(person1.age);//30 根据需要,构造函数可以接受参数 function

深入理解Javascript中构造函数和原型对象的区别

在 Javascript中prototype属性的详解 这篇文章中,详细介绍了构造函数的缺点以及原型(prototype),原型链(prototype chain),构造函数(constructor),instanceof运算符的一些特点.如果对prototype和构造函数不熟悉,可以前往Javascript中prototype属性的详解 和 Javascript 中构造函数与new命令的密切关系 仔细的品味品味.先来做一个简单的回顾. 首先,我们知道,构造函数是生成对象的模板,一个构造函数可以

javascript学习(原型对象)

在javascript中,原型对象我是认为还是比较晦涩难懂的. 在js中我们可以认为js是面对对象的,跟java差不多,本人也是java出身.在js中 对象的理解与java等其他强类型的语言是不一样的,所以会造成很多后端人员学习js这一块会觉得难以理解.但是js这种原型的灵活性也会造成很多的问题,在这里推荐大家看本书<javascript语言精粹>,另外在新的ES6中就引入了class的概念,符合这本书的初衷 对js语言进行"取其精华,去其糟粕". 首先 javascrip

javascript 构造函数方式定义对象 (转载)

javascript 构造函数方式定义对象 javascript是动态语言,可以在运行时给对象添加属性,也可以给对象删除(delete)属性 <html> <head> <script type="text/javascript"> /* //01.定义对象第一种方式 var object =new Object(); alert(object.username); //01.1增加属性username object["username&q