js继承——从创建对象开始
从创建对象开始
创建对象的简单方法就是:使用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继承——从创建对象开始的更多相关文章
- 浅谈JS继承
今天呢,我们来谈谈继承,它也是JS语言中的一大重点,一般什么时候我们会用继承呢,比如有两个拖拽的面板,两个功能基本一致,只是第二个面板多了一些不同的东西,这个时候,我们就会希望,要是第二个直接能继承第 ...
- 老生常谈--Js继承小结
一直以来,对Js的继承有所认识,但是认识不全面,没什么深刻印象.于是,经常性的浪费很多时间重新看博文学习继承,今天工作不是特别忙,有幸看到了http://www.slideshare.net/stoy ...
- Js继承小结
Js继承小结 一直以来,对Js的继承有所认识,但是认识不全面,没什么深刻印象.于是,经常性的浪费很多时间重新看博文学习继承,今天工作不是特别忙,有幸看到了http://www.slideshare.n ...
- js继承的常用方法
写在前面的话:这篇博客不适合对面向对象一无所知的人,如果你连_proto_.prototype...都不是很了解的话,建议还是先去了解一下JavaScript面向对象的基础知识,毕竟胖子不是一口吃成的 ...
- JS继承的一些见解
JS继承的一些见解 js在es6之前的继承是五花八门的.而且要在项目中灵活运用面向对象写法也是有点别扭,更多的时候还是觉得面向过程的写法更为简单,效率也高.久而久之对js的继承每隔一段时间就会理解出现 ...
- JS继承方式详解
js继承的概念 js里常用的如下两种继承方式: 原型链继承(对象间的继承) 类式继承(构造函数间的继承) 由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念.所以,要想实现 ...
- JS继承的原理、方式和应用
概要: 一.继承的原理 二.继承的几种方式 三.继承的应用场景 什么是继承? 继承:子类可以使用父类的所有功能,并且对这些功能进行扩展.继承的过程,就是从一般到特殊的过程.要了解JS继承必须首先要了解 ...
- js继承的方式及其优缺点
js继承方法 前因:ECMAScript不支持接口继承,只支持实现继承 一.原型链 概念:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针,让 ...
- JS继承(简单理解版)
童鞋们,我们今天聊聊js的继承,关于继承,平时开发基本用不到,但是面试没有不考的,我就想问,这是人干的事吗? 好吧,迫于社会主义核心价值观,我们今天就来简单说一说js的继承,谁让它是面向对象编程很重要 ...
随机推荐
- hbase学习(二)hbase单机和高可用完全分布式安装部署
hbase版本 2.0.4 与hadoop兼容表http://hbase.apache.org/book.html#hadoop 我的 hadoop版本是3.1 1.单机版hbase 1.1解 ...
- Nginx 虚拟目录和虚拟主机的配置
nginx.conf 配置文件的几个常用命令 nginx 配置文件主要分为六个区域: main: 全局设置 events: nginx工作模式 http: http设置 sever: 主机设置 loc ...
- gtk+学习笔记(三)
gtk感觉函数好多,需要记好多函数,还是多练习,多总结,今天写了一个登陆窗口,很简单,主要是为了加深对这些东西的记忆,直接贴代码 #include<gtk/gtk.h> static Gt ...
- spring-cloud-sleuth+zipkin追踪服务实现(二)
1. 简述 在上一节<spring-cloud-sleuth+zipkin追踪服务实现(一)>中,我们使用microservice-zipkin-server.microservice-z ...
- PhpStorm函数注释的设置
首先,PhpStorm中文件.类.函数等注释的设置在:setting->Editor->FIle and Code Template->Includes下设置即可,其中方法的默认是这 ...
- C++构造函数详解(复制构造函数)
构造函数是干什么的 该类对象被创建时,编译系统对象分配内存空间,并自动调用该构造函数,由构造函数完成成员的初始化工作,故:构造函数的作用:初始化对象的数据成员. 构造函数的种类 class Compl ...
- Java String、StringBuilder和StringBuffer
转载: Java String.StringBuilder和StringBuffer 概览 在Android/Java开发中,用来处理字符串常用的类有3种: String.StringBuilder. ...
- php抓取一个页面的图片
思路: 1.找到一个页面 2.正则过滤所有的img 3.正则过滤出所有的src的属性 4.获取链接信息,写入文件 file_get_contents(), file_put_contents() 5. ...
- (13) go map
1.定义 map 无序, key唯一 (1) (2) (3)定义+赋值 2. map的值时map, 记得要make 3.增删改查 (1)增 改 (2)删除 (3)查 4.遍历 值map 嵌套for, ...
- Kuhn-Munkres算法
KM算法——二分图最大权匹配 我们前面学过了二分图匹配的匈牙利算法.但这种算法是针对没有权值的图来说的. 肯定有人想问,没有权值的用匈牙利算法,哪有权值的图要求最大权或最小权匹配呢?? 这里就引出了我 ...