前端笔记之JavaScript面向对象(二)内置构造函数&相关方法|属性|运算符&继承&面向对象
一、复习
1.1复习上下文
函数的调用方式 |
上下文 |
fun() |
window |
obj.fun() |
obj |
box.onclick = fun |
box |
setInterval(fun,1000) setTimeout(fun,1000) |
window |
array[8]() |
array |
new fun() |
秘密创建的新对象 |
要看清楚最终的函数调用者是谁。
IIFE也被当做函数直接运行,IIFE的this都是window对象
函数的arguments是类数组对象,比如传入的第0项参数是函数,让它运行:arguments[0](),函数中的上下文是arguments对象。还要知道函数的length和arguments.length的区别。
1.2构造函数
当一个函数用new运算符调用时,此时这个函数叫“构造函数”(constructor)
构造函数四步走:
创建一个新空对象
this绑定给这个空对象
执行语句
返回这个对象
new 出来的所有对象拥有相同属性群,所以可以把构造函数当做类,被new出来的对象都是这个函数的实例。
当构造函数里面有return语句时,注意:
l 如果是return基本类型值,无视这个return,还是返回秘密创建的对象
l 如果是return引用类型值,则不返回原来的对象,而是返回引用类型值
原型链的知识:
构造函数的prototype属性就是实例的__proto__属性。对于一个对象来说,__proto__这个属性叫做自己的原型对象,就是自己的原型链。这个原型链有查找功能,当obj.haha时,obj身上没有haha属性,此时会查找obj.__proto__身上有没有haha属性,并且会继续查找obj.__proto__.__proto__属性身上有没有haha属性……
二、原型链
Object.prototype是所有对象原型链的终点
任何对象都有原型对象(__proto__),最终指向Object.prototype,但是Object.prototype很特殊,它的__proto__终点是null。
JS中,对象是对象、函数、数组、正则等是对象,所有引用类型值都是对象,它们都有__proto__属性。
甚至,xiaoming的__proto__也是一个对象,这个对象也有__proto__。
var obj = {} console.log(obj.__proto__ === Object.prototype); //true
Object()是内置的构造函数,所有的对象,可以认为是Object new出来的
var obj = new Object();
obj.name = "小明";
obj.age = 12;
console.log(obj)
console.log(obj.__proto__ === Object.prototype);
“{}”对象的__proto__都指向Object.prototype,因为它都是Object new出来的。
function People(name,age){
this.name = name;
this.age = age;
}
var xiaoming = new People("小明",12);
console.log(xiaoming.__proto__ === People.prototype); //true
console.log(xiaoming.__proto__.__proto__ === Object.prototype); //true
console.log(xiaoming.__proto__.__proto__.__proto__);; //null
综上所述,xiaoming的原型People.prototype也有原型,小明完整的家谱:
Object.prototype是唯一一个没有__proto__的对象,其他所有对象、函数、数组、正则等都有__proto__
三、内置构造函数
JS内置了很多构造函数,它们也称为“基本类型值”、“引用类型值”的包装类。
3.1引用类型值的构造函数
引用类型值的构造函数:Object()、Function()、Array()、RegExp()
3.1.1 Object()函数
Object()是内置的构造函数,可以直接 new它,返回一个空对象,可以给这个空对象添加属性:
var obj = new Object();
obj.name = "小明";
obj.age = 12;
console.log(obj)
console.log(obj.__proto__ === Object.prototype);
等价于:
var obj = {
name:"小明",
age:12
}
3.1.2 Function()函数
所有function字面量都是它的实例
function sum(a,b){
alert(a+b);
}
sum(3,5);
等价于:
var sum = new Function("a","b","alert(a+b);alert('算完啦!')");
sum(4,5)
在new Function的时候,先罗列所有形参列表,最后一个参数是函数体,注意,参数都是字符串。
console.log(sum.__proto__ === Function.prototype)
任何函数都是Function()构造函数的实例,Object也是Function的实例,Function自己也是自己的实例。Function自己new自己。
console.log(Object.__proto__ === Function.prototype); //true
console.log(Function.__proto__ === Function.prototype); //true
Function和Object的关系:
console.log(Function.prototype.__proto__ === Object.prototype);
console.log(Function.__proto__.__proto__ === Object.prototype);
console.log(Function.__proto__.__proto__ === Object.__proto__.__proto__);
console.log(Function.__proto__ === Object.__proto__);
3.1.3 Array()函数
Array()是系统内置的数组构造函数,任何的数组都是Array() new出来的。
var arr = new Array();
arr[0] = 100;
arr[1] = 200;
arr[2] = 300;
console.log(arr);
等价于:
var arr = [100,200,300];
函数能填参数,表示数组长度,但数组还是空数组:
var arr = new Array(8);
常用的数组方法,都定义在Array.prototype身上。
var arr = [3,3,4,4];
console.log(arr.__proto__ === Array.prototype); //true
console.log(arr.__proto__.__proto__ === Object.prototype); //true
3.1.4 RegExp()函数
任何正则表达式RegExp()函数的实例。
var reg = /\d/g;
//等价于
var reg = new RegExp("d","g");
console.log(reg.__proto__ === RegExp.prototype); //true
console.log(reg.__proto__.__proto__ === Object.prototype); //true
3.2基本类型值“包装类”
【Number()、String()、Boolean()】
基本类型值的构造函数,被称为“包装类”。JS体系为了完整,所以就人为造出了这三个包装类,没有什么用。
3.2.1 Number()函数
用于创建数字对象:
var a = new Number(3);
console.log(a)
console.log(typeof a)
用内置构造函数创建数字的时候,得到一个对象,这对象的原始值属性是:
[[PrimitiveValue]]: 3 //这个属性不可被枚举。
它和字面量创建数字的区别:
var a = new Number(3);
var b = 3;
console.log(a == b); //true
console.log(a === b); //false
用Number()创建的对象,可以参与数学运算:
Number的实例是一个对象,但这个对象一旦参数运算,将变为普通Number类型
var a = new Number(3);
a = a * 3
console.log(a)
console.log(typeof a)
Number()也可以用来把各种值转换为数组(不能转就是NaN),不需要用new调用。
console.log(Number("12")); //
console.log(Number("12年")); //NaN
console.log(Number("")); //
console.log(Number(false)); //
console.log(Number(true)); //
console.log(Number({})); //NaN
console.log(Number([])); //
console.log(Number([1,2])); //NaN
任何需要转为数字的隐式转换,实际上就是在调用Number函数。
3.2.2 String()函数
var str = new String("我喜欢你");
console.log(str)
String()也可以用来转换:
console.log(String(123)); //"123"
console.log(String(true)); //"true"
console.log(String([])); //""
console.log(String([1,2,3])); //"1,2,3"
console.log(String(NaN)); //"NaN"
console.log(String({})); //"[Object Object]"
3.2.3 Boolean()函数
不管值是false还是true,都能通过if的验证,都是true。
var b = new Boolean(false);
console.log(b)
console.log(typeof b);
if(b){
alert("真的");
}
3.3内置构造函数之间的关系
就三句话,死记:
1、“{}”对象是被Object new出来的。所以它的__proto__就会指向Object.prototype。
2、任何函数都是Function new出来的实例,所以只要它是函数(构造函数也是函数),它的__proto__就会指向Function.prototype。
3、Function是所有构造函数的妈,它自己也是自己的妈。
小明不是Object new出来的,是People new的,它的__proto__指向People.prototype。
console.log(Object.__proto__.__proto__ === Object.prototype); //true
console.log(Function.__proto__.__proto__ === Object.prototype); //true
console.log(Object.__proto__ === Function.prototype); //true
console.log(Function.__proto__ === Function.prototype); //true
console.log(Array.__proto__ === Function.prototype); //true
console.log(RegExp.__proto__ === Function.prototype); //true
console.log(Number.__proto__ === Function.prototype); //true
console.log(String.__proto__ === Function.prototype); //true
console.log(Boolean.__proto__ === Function.prototype); //true
四、相关的方法、属性、运算符
4.1 hasOwnProperty()方法
返回布尔值(true/false),用来检测某属性、某方法是不是在自己身上。
function People(name){
this.name = name;
}
People.prototype.sayHello = function(){
alert("你好");
}
var xiaoming = new People("小明");
console.log(xiaoming.hasOwnProperty("name")); //true
console.log(xiaoming.hasOwnProperty("sayHello")); //false
console.log(xiaoming.hasOwnProperty("toString")); //false
4.2 in运算符
返回布尔值(true/false),in运算符可以检查某个对象有没有能力调用某属性、某方法,而不管这个属性或方法是否定义在自己身上,还是原型身上。
字符串 in 对象 function People(name){
this.name = name;
}
People.prototype.sayHello = function(){
alert("你好");
}
var xiaoming = new People("小明");
console.log("name" in xiaoming); //true
console.log("sayHello" in xiaoming); //true
console.log("toString" in xiaoming); //true
4.3 constructor属性
每一个函数的prototype对象都有一个constructor属性,指向构造函数。
function People(name){
this.name = name;
}
var xiaoming = new People("小明");
console.log(People.prototype)
console.log(People.prototype.constructor === People); //true
console.log(People.prototype.hasOwnProperty("constructor")); //true
console.log(xiaoming.constructor === People); //true
console.log(xiaoming.hasOwnProperty("constructor")); //false
4.4 instanceof运算符
返回布尔值,用来检查某个对象是不是某个函数的实例
o instanceof F
如果F.prototype在o的原型链上,返回true,否则返回false
function People(name){
this.name = name;
}
var xiaoming = new People("小明");
function Dog(){
}
console.log(xiaoming instanceof People); //true
console.log(xiaoming instanceof Object); //true
console.log(xiaoming instanceof Dog); //false
小题目:
console.log(Object instanceof Object); //true
console.log(Function instanceof Function); //true
console.log(Function instanceof Object); //true
console.log(Number instanceof Function); //true
console.log(Number instanceof Number); //false
我们发现object.prototype是所有对象原型链的终点,所以我敢说任何原型X一定true。
x instanceof Object Function的prototype出现在自己的__proto__线上,所以是true
console.log(Function instanceof Function); //true
五、练习题
5.1题目1
function A(){}
function B(){
return new A(); //返回了引用类型值
}
A.prototype = B(); //返回了一个A的实例1
B.prototype = new B();//返回了一个A的实例2
var a = new A(); //返回了一个A的实例,赋给a
var b = new B(); //返回了一个A的实例,赋给b console.log(a.__proto__ == b.__proto__);
console.log(a instanceof A); //true
console.log(a instanceof B); // false
console.log(b instanceof A); //true
console.log(b instanceof B); //false
5.2题目2
[].constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor.constructor === Function
答案:true。
六、继承
6.1什么是继承
计算机领域,关注两个类的关系,就是看属性群之间的关系。
比如:人类和狗狗类属性群,难免会有交集,但是不完全重合,此时可以认为两个类没有任何关系。
看看人和学生的属性群:
l 小学生肯定是人,人的属性学生全有,人能做的事情学生都能做。
l 但是反过来,小学生的属性和能力,人不一定有。
我们说:
“学生”细化了、精分了、更具体了“人”。
“学生”的实例要比“人”的实例少。
“学生”一定是人,但“人”不一定是学生。
术语上,我们称“学生类”继承(extend)“人类”。人类叫“父类(超类)”,学生类叫“子类”。
人又继承谁呢?人继承哺乳动物,哺乳动物继承“生物”...
此时计算机中小学生类继承(extend)人类。
A继承了B,此时要意识到:
A拥有B的所有属性和方法
A的属性群比B大
A丰富了B,A把B变得更具体,范围更小。
6.2 JavaScript实现继承
JavaScript实现两个类:People类,Student类,要求People类拥有的属性和方法,Student类的实例也要拥有People的属性和方法。Student还能丰富自己类的属性和方法,很简单,只要求巧妙设计原型链。
//人类
function People(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
}
People.prototype.sayHello = function(){
alert("你好,我是" + this.name);
}
People.prototype.sing = function(){
alert("都拉米发骚啦稀~~~");
}
// 学生类
function Student(name,age,sex,id,banji,socre){
People.apply(this, arguments)
// this.name = name;
// this.age = age;
// this.sex = sex;
this.id = id;
this.banji = banji;
this.socre = socre;
}
//下面这条语句可以实现继承
Student.prototype = new People();
Student.prototype.study = function(){
alert(this.name + "在学习!");
}
var xiaoming = new Student("小明",12,"男",100001,"初三一班", 100)
xiaoming.study();
xiaoming.sayHello();
xiaoming.sing();
注意:红色语句一定要出现在Student.prototype.*** = function(){}之前。
jQuery创始人John Resig写了一个小包,20多行代码,解决了JS继承恶心的问题。
https://johnresig.com/blog/simple-javascript-inheritance/
引包之后,这个包改变我们创建JS类的方式(和jQuery一样改变了写JS的方式)
//人类
var People = Class.extend({
init : function(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
},
sayHello:function(){
alert("你好,我是" + this.name);
},
sing:function(){
alert("都拉米发骚啦希~~~");
}
}) //学生类
var Student = People.extend({
init : function(name,age,sex,id,banji,socre){
this._super(name,age,sex); //继承父类的属性
// this.name = name;
// this.age = age;
// this.sex = sex;
this.id = id;
this.banji = banji;
this.socre = socre;
},
study :function(){
alert(this.name + "在学习!");
}
})
var xiaoming = new Student("小明",12,"男",100001,"初三一班", 100)
console.log(xiaoming)
xiaoming.study();
xiaoming.sing();
七、上升到面向对象
面向对象是一种编程思想,两个字就能概括:自治(自己管理自己),深入理解,就是封装。每个对象个体仅需要管理自己即可。
面向对象初学阶段,当你遇见大量的结构、功能、性质、什么都一样的对象的时候,立刻想到用面向对象技术。
现在要给大家一个思维定式,面向对象的时候怎么编程:
思考初程序中有哪些类,在前期我们的业务仅仅只有一个类,后期类会有多个。
每个类有哪些方法和属性,就是他们自己有什么功能
每个类之间如何通信、交互数据、此时就要用到设计模式,比如中介者模式、发布订阅模式(观察者模式)。
这个类怎么进行单元测试,如果保证自己这个类鲁棒,每个类都鲁棒了,整个程序就鲁棒。
我们之前的编程叫“面向过程”,现在是“面向对象”编程(OO)
7.1面向对象-红绿灯(案例)
考虑一个问题,页面上要制作一个效果:100个红绿灯,点击某一个红绿灯,从红灯变黄灯,再次点击从黄灯变绿灯,再次点击就绿灯变红灯...
有一个信号量,点击按钮之后,信号量变化0、1、2、0、1、2、0、1、2...然后让div的background-position进行变化,你要写100个信号量、100个盒子、100个事件。
页面上出现的东西就是红绿灯,而且它们拥有相同的样子、性质、功能,所以可以让红绿灯设计成为一个类。
每一个类负责什么:①状态量 ②DOM元素。
每个JS对象中有两个属性,一个是状态属性,另一个是DOM对象
简单的说,DOM对象现在成为JS对象的一个属性。
这个类有哪些属性?
DOM属性
颜色属性 哪些方法?
初始化方法 init()
换颜色方法 changeToColor()
绑定事件方法 bindEvent()
第一步:DOM结构和CSS样式,确保放一个div元素能看见灯出来了。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Document</title>
<style type="text/css">
*{ margin: 0; padding: 0;}
div.honglvdeng{
position: relative;
width: 140px;
height: 328px;
background: url(./images/honglvdeng.jpg);
}
</style>
</head>
<body>
<div id="box">
<div class="honglvdeng"></div>
</div>
</body>
</html>
//第二步:创建红绿灯类
//new Honglvdeng()时,会执行构造函数中的语句
//所以在构造函数中创建一个DOM对象,然后让它上树
function Honglvdeng(){
//每一个类中有两个属性:状态量、DOM
this.dom = null;
//状态属性
this.state = 0;
//初始化方法
this.init();
//事件监听方法
this.bindEvent();
}
//为了程序美观,整洁,好更改和可插拔性高,方便维护,将DOM和上树语句都写在初始化方法中
Honglvdeng.prototype.init = function(){
//创建DOM
this.dom = document.createElement('div');
//给DOM添加类名
this.dom.className = 'honglvdeng';
//上树
document.getElementById("box").appendChild(this.dom);
} //第三步:添加事件监听
Honglvdeng.prototype.bindEvent = function(){
//备份this,因为事件监听里面的this表示dom元素本身
var self = this;
this.dom.onmouseenter = function(){
// 改变信号量
// self.state++;
// if(self.state > 2) self.state = 0
//判断简写
self.state = ++self.state % 3;
self.dom.style.backgroundPositionX = -155 * self.state +'px';
}
}
//第四步:实例化100个红绿灯
var count = 100;
while(count--){
new Honglvdeng();
}
前端笔记之JavaScript面向对象(二)内置构造函数&相关方法|属性|运算符&继承&面向对象的更多相关文章
- 34、JavaScript面向对象(内置构造函数&相关方法|属性|运算符&继承&面向对象)
一.面向对象 1.1 this的指向问题 要看清楚最终的函数调用者是谁. IIFE也被当做函数直接运行,IIFE的this都是window对象 函数的arguments是类数组对象,比如传入的第0项参 ...
- 前端笔记之JavaScript(二)关于运算符&初识条件判断语句
运算符 数学运算符的正统,number和number的数学运算,结果是number.出于面试的考虑,有一些奇奇怪怪的数学运算: 数学运算中:只有纯字符串.布尔值.null能够进行隐式转换. //隐式转 ...
- js内置构造函数属性修改问题
在学习js原型时遇到一个问题,Array,Object等内置构造函数部分属性无法修改,我猜测可能是因为浏览器实现的原因造成的. 1.修改name属性无效. <script type=" ...
- javaScript中Math内置对象基本方法入门
概念 Math 是javaScript的内置对象,包含了部分数学常数属性和数学函数方法. Math 不是一个函数对象,用户Number类型进行使用,不支持BigInt. Math 的所有属性与方法都是 ...
- javascript中的内置对象
2015.12.1 javascript中的内置对象 复习: 1.js中的内置函数 alert prompt write parseInt parseFloat eval isNaN document ...
- python面向对象的基础语法(dir内置函数、self参数、初始化方法、内置方法和属性)
面相对象基础语法 目标 dir 内置函数 定义简单的类(只包含方法) 方法中的 self 参数 初始化方法 内置方法和属性 01. dir 内置函数(知道) 在 Python 中 对象几乎是无所不在的 ...
- JavaScript中的内置函数
JavaScript中的内置函数 制作人:全心全意 在使用JavaScript语言时,除了可以自定义函数之外,还可以使用JavaScript的内置函数,这些内置函数是由JavaScript语言自身提供 ...
- day34 反射、面向对象内置方法:如__str__、面向对象的软件开发
Python之路,Day21 = 反射.面向对象内置方法:如__str__.面向对象的软件开发 几个内置查看的方法使用 .__base__ 查看类的继承结构.mro() 对象找属性的顺序存在里面 -- ...
- Flutter学习笔记(36)--常用内置动画
如需转载,请注明出处:Flutter学习笔记(36)--常用内置动画 Flutter给我们提供了很多而且很好用的内置动画,这些动画仅仅需要简单的几行代码就可以实现一些不错的效果,Flutter的动画分 ...
随机推荐
- User Profile Service服务未能登录,无法登录
不知你是否遇到这样的问题,某一天你打开PC,开机正常,可当你输入正确的密码回车,却发现Vista或Win7拒绝让你登录,提示"User Profile Service 服务未能登录.无法加载 ...
- Lucene 源码分析之倒排索引(二)
本文以及后面几篇文章将讲解如何定位 Lucene 中的倒排索引.内容很多,唯有静下心才能跟着思路遨游. 我们可以思考一下,哪个步骤与倒排索引有关,很容易想到检索文档一定是要查询倒排列表的,那么就从此处 ...
- Oracle系列-锁表与解锁解决方案(基础版)
[Oracle锁表查询和解锁解决方案] 一.了解原因(借鉴整理) 数据库操作语句的分类 DDL:数据库模式定义语言,关键字:createDML:数据操纵语言,关键字:Insert.delete.upd ...
- 你可能忽略的js类型转换
前言 相信刚开始了解js的时候,都会遇到 2 == '2',但 1+2 == 1+'2'为false的情况.这时候应该会是一脸懵逼的状态,不得不感慨js弱类型的灵活让人发指,隐式类型转换就是这么猝不及 ...
- JAVA基础第五章-集合框架Map篇
业内经常说的一句话是不要重复造轮子,但是有时候,只有自己造一个轮子了,才会深刻明白什么样的轮子适合山路,什么样的轮子适合平地! 我将会持续更新java基础知识,欢迎关注. 往期章节: JAVA基础第一 ...
- DBA_OBJECTS
类型:View Owner:SYS 内容:记录了数据库中所有的对象 字段: OWNER:对象的Owner OBJECT_NAME:对象名称 SUBOBJECT_NAME:对象的子对象名字,例如分区 O ...
- 理解 KMP 算法
KMP(The Knuth-Morris-Pratt Algorithm)算法用于字符串匹配,从字符串中找出给定的子字符串.但它并不是很好理解和掌握.而理解它概念中的部分匹配表,是理解 KMP 算法的 ...
- 软件测试自动化的最新趋势对开源测试管理软件ITEST的启示
https://www.infoq.cn/article/c-LHJS2ksuDxp1WkrGl4 理面提到几点,DevOps 的关键原则是开发团队.测试团队和运营团队协作,无缝发布软件.这意味着集中 ...
- 前端笔记之NodeJS(二)路由&REPL&模块系统&npm
一.路由机制(静态资源文件处理) 1.1 Nodejs没有根目录 MIME类型:http://www.w3school.com.cn/media/media_mimeref.asp 在Apache中, ...
- .net Lambda表达式与Linq (LINQ TO object)
Lambda表达式,是用来写匿名方法的. 在委托用得比较多,因为委托是传递方法的. 定义几个委托: public delegate void DoNoThing();//无参无返回值 publ ...