一、对象(object)
1.对象的创建
对象属于JS的引用类型。其创建方式一共有两种。
- 字面量方式
var obj = {
"age" : 18,
"name" : "panda",
"sex" : "girl"
}
{}
就是对象的界定符,就是对象的字面量。观察对象可知,对象就是无序属性的集合。
标准的对象创建格式。
{
k : v,
k : v,
k : v,
k : v
}
一般情况下 k 可以不加引号,但当 k 满足以下条件:(必须的加引号)
k 是特殊字符
k 是数字
k 是有空格
k 是关键字、保留字
JSON 和对象字面量 的区别:
JSON 的 k 必须加引号。JSON加引号原理其实很简单,因为 JSON 需要为其他后台语言服务,很明显是为了兼容其他语言才强调必须加引号。所以为了方便,我写对象也全部加上引号。
- new 构造函数方式
var obj = new Object();
obj.age = 18;
obj.name = "panda";
obj.sex = "girl";
上面两种方式创建出来的对象,是相同的。字面量的方式直观、简单、并且有“封装”的感觉。所以我们鼓励大家用字面量来创建对象。两种方法最好不要杂糅,不要创建个空对象,通过第二种方法,往里面打点添加方法,但是你要这么干了的话,好吧是可以的!
2.对象属性值
对象属性值,可以是任何东西。比如数字、字符串、布尔值、正则表达式、对象、数组、函数……特殊的是:当对象的属性值为函数,那么就称这个属性是这个对象的方法。
3.对象调用
- 打点法(不能用于上面列的特殊k)
console.log(obj.age);
- 方括号法(万能)
console.log(obj[age]);
二、this 到底是谁
在对象中我们经常用到 this ,除此之外在函数、定时器、等等中也会用到 this,那么这些调用方式里面的 this,到底指代的是谁?
● 直接用()
运算符来调用函数,那么函数里面的 this 指的是 window 对象
● 函数如果绑定给了某个 HTML 元素的事件上,那么函数里面的 this 就是这个 HTML 对象
● 用定时器调用函数,函数内部的 this 就是 window 对象(所以传进构造函数里面的 this 必须进行备份,通常用 that 或 self 备份)
● 用对象打点(方法)来调用函数,函数里面的 this 指的是这个对象
● 用apply、call,函数强行绑定对象,this 指的就是这个绑定的对象。
三、构造函数
构造函数的创建和一般的函数是相同的,不过一般构造函数的函数名首字母大写,区分于普通函数。
JavaScript 规定,一个函数可以用 new 关键字来调用,new是运算符。实例如下:
function Ball(width,height,radius){
this.width = width;
this.height = height;
this.radius = radius;
}
var basketball = new Ball(100,100,10);
new 一个函数的时候,函数里面的语句会执行。
那么此时这个函数将按顺序发生四件事情:
- 隐秘的创建一个新的空对象
- 将这个函数里面的 this 绑定到刚才创建隐秘新对象上
- 执行函数体里面的语句
- 返回这个新的对象
一般我们称 basketball 是 Ball 这个类的实例。从这个实例可以看出,JavaScript 中,没有类的概念。是通过构造函数的4步走机制来创建类似的对象,勉强可以看为类。JS 这个语言是“基于对象”(base Object)的语言,不能叫做“面向对象”(object-oriented )的语言。
四、构造函数的原型(prototype)
首先我们要明白两件很重要的事:
- 一个函数的原型,对于普通函数来说,没任何鸟用。但是如果函数是一个构造函数,那么函数的原型,就是专门用来放复用的函数!
- 所有的属性要绑在对象身上,而所有的方法,定义在对象的原型对象中,如果定义在构造函数里面多次调用的时候函数没有发生复用。
在 JavaScript 中,任何一个函数,都有一个prototype 属性,指向一个对象。我们输出了一个函数的prototype属性,你会发现是一个空对象。输出这个 prototype 的类型,发现是object 类型。
prototype 就是英语“原型”的意思。每个函数都有原型,原型是一个对象。
原型的添加方式:
- 第一种,追加属性:
Ball.prototype.init = function(){
alert(this.name);
}
- 第二种,直接覆盖整个原型:
Ball.prototype = {
init : function(){
alert(this.name + this.age);
}
}
第二种方法,不能使用Ball.prototype.constructor
访问构造函数 Ball 了。也是就说 constructor 无效了。如果想让 constructor 恢复,只能通过如下写法添加。
Ball.prototype = {
consructor: Ball,
init : function(){
alert(this.name + this.age);
}
}
五、原型链
所谓的原型链,就是proto的链条。
prototype 我们称为“原型”,只有函数有原型
__proto__
我们称为“原型对象”,任何对象都有原型对象。
原型链主要用于原型链的查找:
当我们试图访问一个对象身上的属性的时候,如果这个对象身上有这个属性,则返回它的值。如果它身上没有这个属性,那么将访问它的原型对象,检测它的原型对象身上是否有这个值,如果有返回它原型对象身上的这个值。
但是世界上只有一个对象没有原型对象,这个对象就是 Object.prototype,系统内置的 object 是所有对原型的终点。
基本类型和内置类型的内置对象:
- 所有的引用类型值,都有内置构造函数。比如
new Object()
new Array()
new Function()
new RegExp()
new Date()- 基本类型值,也有包装类型。所谓包装类型,就是它的构造函数。
new Number()
new String()
new Boolean()
六、继承
构造函数 student 的原型(prototype)指向另一个实例,这样 student 就可以继承 People实例里面的函数和原型。
//核心语句,继承的实现全靠这条语句了:
Student.prototype = new People();
七、对象与属性
- in运算符
in不仅仅检测是对象自己有没有这个属性,如果原型链上有这个属性,那么也会返回true。
console.log("a" in obj);
- for in
这个循环,会把原型链上所有的可枚举的属性列出来:
for(var k in obj){
console.log(k);
} - hasOwnProperty方法
这个方法定义在了 Object.prototype 对象上面,所以任何一个 Object 都能够拥有这个方法。
这个方法返回true、false。表示自己是否拥有这个属性,不考虑原型链。就看自己身上有没有这个属性,不进行原型链查找。
console.log(obj.hasOwnProperty("a"));
- instanceof运算符
A instaceof B
验证 A 对象是不是 B 类的实例。
八、闲扯
通过学习面向对象可以发现,面向对象可以对事件进行批量控制,而不用担心代码的复用程度过低,这其实就类似组件开发了,也就是接近面向编程的思想了。