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的继承,谁让它是面向对象编程很重要 ...
 
随机推荐
- C/C++——C语言跳出多重循环方法
			
c语言的break语句只能跳出离它最近的一层循环,但是我们有时候需要跳出多层循环,以下有几种跳出多重循环的方法: 1. 使用goto ; i < MAX1; i++) { ; j < MA ...
 - Nginx源码分析-ngx_module_s结构体
			
该结构体是整个Nginx模块化架构最基本的数据结构体.它描述了Nginx程序中一个模块应该包括的基本属性,在tengine/src/core/ngx_conf_file.h中定义了该结构体 struc ...
 - solr应用
			
Solr是apache的顶级开源项目,它是使用java开发 ,基于lucene的全文检索服务器.Solr比lucene提供了更多的查询语句,而且它可扩展.可配置,同时它对lucene的性能进行了优化. ...
 - rcnn ->fast rcnn->faster rcnn物体检测论文
			
faster rcnn中的rpn网络: 特征可以看做一个尺度51*39的256通道图像,对于该图像的每一个位置,考虑9个可能的候选窗口:三种面积{1282,2562,5122}×三种比例{1:1,1: ...
 - 推荐一个数据相关的网站tushare
			
推荐一个网站:tushare 使用方法如下: pip install tushare 我是使用pycharm直接安装的 抓取了浦发和光大的股票数据,并通过csv进行保存,和通过plt进行图片打印 im ...
 - LeetCode解题报告—— Best Time to Buy and Sell Stock
			
Best Time to Buy and Sell Stock Say you have an array for which the ith element is the price of a gi ...
 - Django admin后台操作
			
Django提供自动后台管理应用,简称admin. admin是一个应用,每个Web站点都需要它.admin通过让开发者可以在完成完整的UI之前验证处理数据的代码. 设置admin 打开setting ...
 - 如何关闭WordPress后台的主题、插件、版本更新通知?
			
由于WordPress 更新速度非常快,不论是主题 插件或是版本,每个月少说要执行个好几次,因为更新快,所以WordPress后台加入了更新通知,提醒使用者有新版本了,可以进行插件.主题或是系统更新, ...
 - AC日记——830A - Office Keys
			
思路: 背包: 代码: #include <cmath> #include <cstdio> #include <cstring> #include <ios ...
 - Scrapy 增加随机请求头 user_agent
			
原文: 为什么要增加随机请求头:更好地伪装浏览器,防止被 Ban. 如何在每次请求时,更换不同的 user_agent,Scrapy 使用 Middleware 即可 Spider 中间件 (Midd ...