从创建对象开始

创建对象的简单方法就是:使用Object构造函数或者对象字面量。但这两个方法有个缺点:创建相同对象,要编写大量重复代码。

为了避免这个问题——>工厂模式:用函数封装以特定接口创建对象

function createPerson(name, age){
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function(){
return this.name;
}
return o;
}
var p1 = createPerson("Tom", 23);
var p2 = createPerson("Joe", 20)
p1 instanceof createPerson //false

工厂模式:优点: 解决了创建多个相似对象问题   缺点:没有解决对象识别问题(不知道对象的类型)

为了解决对象识别问题——>构造函数模式:创建特定类型的对象

function Person(name, age){
this.name = name;
this.age = age;
this.sayName = function(){
return this.name;
}
}
var p1 = new Person("Tom", 23);
var p2 = new Person("Joe", 20);
p1 instanceof Person //true 检测对象类型
p1.constructor === Person //true 识别对象类型 p1.sayName === p2.sayName //false

构造函数模式:Person()与createPerson()   不同之处:没有显示创建对象、将属性方法值赋值给this、没有return 语句,还有就是函数名一个字母大写。

构造函数也是函数,那么函数用new执行会发生什么呢(重点)

1.创建一个空对象。

2.将构造函数的作用域赋值给新对象(this指向该对象, 同时还继承了该函数的原型)。

3.执行构造函数中的代码(添加属性和方法)

4.隐式的返回this(返回该对象, 如果没有显示的返回其他对象的话)

上面说了构造函数也是函数,只是使用了new 调用,如果不使用new就和普通函数一样

var wp = Person("Marry", 18);
window.sayName(); //"Marry"
wp.sayName(); //TypeError: Cannot read property 'sayName' of undefined
sayName() //"Marry"

构造函数解决了对象识别问题,但是缺点:正如前面(p1.sayName === p2.sayName //false )会导致不同作用域链和标识符解析

//构造函数中的
this.sayName = function(){
return this.name;
}
//等价于
this.sayName = new Function("return this.name;")

为了解决这个问题,我们可以把sayName函数放外面作为全局函数,但这方法缺点颇多,很不合适。于是...

出现了——>原型模式:函数有个prototype属性,指向一个对象,该对象可以包含由特定类型的所有实例共享的属性和方法,简称之prototype是p1,p2的原型对象。这个原型对象可以让所有实例共享它包含的方法和属性。

function Person(){}
Person.prototype.name = "Tom";
Person.prototype.age = 20;
Person.prototype.friends = ["A", "B", "C"];
Person.prototype.sayName = function(){
return this.name;
}
var p1 = new Person();
var p2 = new Person();
p1.sayName === p2.sayName; //true p1.name = "other";
p2.friends.push("D");
p1.sayName(); // "other" ---来自实例
p2.sayName(); // "Tom"; ---来自原型 p1.friends; //["A", "B", "C", "D"] ----引用类型
p2.friends; //["A", "B", "C", "D"] Person.prototype.isPrototypeOf(p1) //true
Object.getPrototypeOf(p1) === Person.prototype //true //in 通过对象能访问给定属性就返回true,不管实例还是原型
"name" in p1; //true
"name" in p2; //true

// hasOwnProperty() 只返回实例中的属性
p1.hasOwnProperty("name"); //true
p2.hasOwnProperty("name"); //false //Object.keys() 返回对象上所有可枚举实例属性
Object.keys(Person.prototype); //["name", "age", "friends", "sayName"]
Object.keys(p1); //["name"]

//Object.getOwnPropertyNames() 返回所有实例属性,无论是否可枚举
Object.getOwnPropertyNames(Person.prototype) //["constructor", "name", "age", "friends", "sayName"]
Object.getOwnPropertyNames(p1) //["name"]

说明:实例,构造函数,原型的关系:实例的[[Prototype]](__proto__)只指向原型、构造函数的prototype属性指向原型、原型的constructor指向构造函数。

in操作符:在<= IE8中 in不会枚举[[Enumerate]]为false的同名属性 ;在safari3中 in会枚举被隐藏的属性。 所以in慎用。

其中上述代码

Person.prototype.name = "Tom";
Person.prototype.age = 20;
Person.prototype.friends = ["A", "B", "C"];
Person.prototype.sayName = function(){
return this.name;
}
//可写成: ---相当于重写原型
Person.prototype = {
constructor: Person,
name = "Tom",
age = 20,
friends = ["A", "B", "C"],
sayName = function(){
return this.name;
}
} //支持ES5中,可去掉 上句 constructor: Person,添上如下代码:
Object.defineProperty(Person.prototype, "constructor", {
enumerate: false,
value: Person
});

原型模式:虽然解决了构造函数的缺点问题,但缺点: 1.默认情况下取相同的值;2.引用类型的实例被很多实例共享

为了避免这些问题——〉组合使用构造函数和原型模式:构造函数模式用于定义实例属性,而原型模式用于定义方法和共享属性, 最大限度的节省了内存

function Person(name, age){
this.name = name;
this.age = age;
this.friends = ["A", "B", "C"];
}
Person.prototype = {
constructor: Person,
sayName: function(){
return this.name;
}
}
var p1 = new Person("Tom", 34);
var p2 = new Person("Joe", 21);
p1.friends.push("D");
p1.friends //["A", "B", "C", "D"]
p2.friends //["A", "B", "C"]
p1.sayName === p2.sayName; //true

组合模式:优点:集两模式优点于一身,极好!因此该模式使用最广泛、认知度最高。

东西一好,就有人挑骨头,其他oo语言开发经验者看到独立的构造函数与原型会觉得很困惑,于是...

出现了——>动态原型模式:将所有信息封装在构造函数中

function Person(name, age){
this.name = name;
this.age = age;
this.friends = ["A", "B", "C"];
if (typeof this.sayName != "function") {
Person.prototype.sayName = function(){
return this.name;
}
}
} //创建第一个实例才会执行,此后,原型完成初始化
var p1 = new Person("Tom", 23);
p1.sayName(); //"Tom"

至此,如果都不适用的话...

出现了——〉寄生构造函数模式:创建一个函数,作用仅仅是封装创建对象的代码,然后再返回新创建的对象

function Person(name, age){
var o = new Object();
o.name = name;
o.age = age;
o.sayName = function(){
return this.name;
}
return o;
}
var p1 = new Person("Tom", 23);
p1.sayName();

该模式准确的说与工厂模式一模一样。只是把该函数当构造函数调用(使用new)而与构造函数模式相似,又有点不同,这不同之处就是:显示的创建对象,重写了返回值。

既然如此,这个模式的优势在哪里呢?对于构造函数模式而言,它可以new一个除object类型之外的其他类型——在不扩展原生构造函数的情况下自定义一个扩展型的构造函数。

function SpecialArray(){
var values = new Array();
values.push.apply(values, arguments);
values.toPipedString = function(){
return this.join("|");
};
return values;
}
var friends = new SpecialArray("A", "B", "C");
friends.toPipedString(); //"A|B|C"
friends instanceof SpecialArray //false
friends instanceof Array //true

说明:构造函数返回的对象与构造函数或者构造函数的原型之间没有任何关系,也就是说构造函数外面创建或者里面创建是没有区别的,(只是寄生在构造函数中)因此无法用instanceof来识别对象。

还有一种创建对象的方法:——>稳妥构造函数模式:没有公共属性,不使用this、new,适合安全环境下使用

function Person(name, age){
}
function Person(name){
var o = new Object();
o.sayName = function(){
return name;
}
return o;
}
var p1 = Person("Tom");
var p2 = Person("Joe");
p1.name //undefined
p2.name //undefined
p1.sayName() //"Tom"
p2.sayName() //"Joe" 传入构造函数的name之恩那个通过sayName()访问

稳妥构造函数模式与寄生构造函数模式类似:创建的对象与构造函数之间没有任何关系。所以无法用instanceof来识别对象。

该博客与js高级程序设计内容相似,加之自己的理解与总结,不对之处欢迎指出。详情可看js高级程序设计。

js继承——从创建对象开始的更多相关文章

  1. 浅谈JS继承

    今天呢,我们来谈谈继承,它也是JS语言中的一大重点,一般什么时候我们会用继承呢,比如有两个拖拽的面板,两个功能基本一致,只是第二个面板多了一些不同的东西,这个时候,我们就会希望,要是第二个直接能继承第 ...

  2. 老生常谈--Js继承小结

    一直以来,对Js的继承有所认识,但是认识不全面,没什么深刻印象.于是,经常性的浪费很多时间重新看博文学习继承,今天工作不是特别忙,有幸看到了http://www.slideshare.net/stoy ...

  3. Js继承小结

    Js继承小结 一直以来,对Js的继承有所认识,但是认识不全面,没什么深刻印象.于是,经常性的浪费很多时间重新看博文学习继承,今天工作不是特别忙,有幸看到了http://www.slideshare.n ...

  4. js继承的常用方法

    写在前面的话:这篇博客不适合对面向对象一无所知的人,如果你连_proto_.prototype...都不是很了解的话,建议还是先去了解一下JavaScript面向对象的基础知识,毕竟胖子不是一口吃成的 ...

  5. JS继承的一些见解

    JS继承的一些见解 js在es6之前的继承是五花八门的.而且要在项目中灵活运用面向对象写法也是有点别扭,更多的时候还是觉得面向过程的写法更为简单,效率也高.久而久之对js的继承每隔一段时间就会理解出现 ...

  6. JS继承方式详解

    js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念.所以,要想实现 ...

  7. JS继承的原理、方式和应用

    概要: 一.继承的原理 二.继承的几种方式 三.继承的应用场景 什么是继承? 继承:子类可以使用父类的所有功能,并且对这些功能进行扩展.继承的过程,就是从一般到特殊的过程.要了解JS继承必须首先要了解 ...

  8. js继承的方式及其优缺点

    js继承方法 前因:ECMAScript不支持接口继承,只支持实现继承 一.原型链 概念:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针,让 ...

  9. JS继承(简单理解版)

    童鞋们,我们今天聊聊js的继承,关于继承,平时开发基本用不到,但是面试没有不考的,我就想问,这是人干的事吗? 好吧,迫于社会主义核心价值观,我们今天就来简单说一说js的继承,谁让它是面向对象编程很重要 ...

随机推荐

  1. 报错:/application/zabbix/sbin/zabbix_server: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object file: No such file or directory

    启动zabbix_server时报错: /application/zabbix/sbin/zabbix_server: error while loading shared libraries: li ...

  2. leetcode 168. Excel Sheet Column Title 171 Excel Sheet Column Number

    题目 //像10进制一样进行 转换   只是要从0开始记录 class Solution { public: string convertToTitle(int n) { char a; string ...

  3. C语言小程序之整除

    看到有人要求用C语言写这样一个小程序,就拿来温习一下 需求:输出从1到2015这2015个自然数中,能被4或5整除,但不能被30整除的数,并计算有多少个数.   #include<stdio.h ...

  4. 得分(UVa1585)

    题目具体描述见:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_prob ...

  5. 找到最大或最小的N个元素---heapq模块

    堆排序heapq的用法 基本用法: 复杂数据结构: # coding=utf- # example.py # Example of using heapq to find the N smallest ...

  6. [实战]MVC5+EF6+MySql企业网盘实战(5)——登录界面,头像等比例压缩

    写在前面 关于该项目,已经很久没更新了.实在是找不到一个好的ui,没办法就在网上找了一个还不错的,就凑合着先用着吧,先出第一版,以后的再想着去优化.最近更新与网盘项目相关的内容是准备在项目中使用一个美 ...

  7. C# HTML 生成 PDF

    原文出处:http://www.cnblogs.com/shanyou/archive/2012/09/07/2676026.html

  8. 在linux下安装sbt

    1.到官方网站下载deb包,下载地址:https://dl.bintray.com/sbt/debian/sbt-1.0.3.deb 2.点击下载的deb包进行安装 3.安装完成后,在terminal ...

  9. php大图

    原文地址:https://laravel-china.org/articles/9450/php-fpm-vs-swoole

  10. 关于在vue里使用脚手架空行、空格会报错的问题

    第一种方法: 重新用脚手架安装项目,在命令行里选择Use ESLint to lint your code?这项是输入  n 第二种方法: 找到build文件夹下的 webpack.base.conf ...