就是找个工具,帮我完成一项工作,对象就像一个工具一样,每个工具都可以帮我们实现某个功能,比如汽车可以实现运输,我们只需要学会如何去开动汽车,而不需要知道汽车是如何实现开动的。面向对象的好处:我们所有的项目都是团队作战。通过对象实现任务分离。用对象的某一部分实现一项功能,可以实现团队作战。对象实质上就是一个包含多个工具的工具包,用对象来实现对功能的分类管理。
比如一个字符串对象,有toString,substring,subStr,indexOf,lastIndexOf等函数,用来实现不同的功能。
在对象中可以包含属性,方法,通过点语法来访问对象的属性和方法。
相当于组装一辆汽车。汽车是一个对象,我们需要让汽车有移动,刹车等功能。我们先要定义这个对象,就是构造函数。然后给汽车添加轮胎,发动机等,就相当于添加属性,我们让汽车跑起来,刹车,就相当于添加方法。而一个刹车系统,相当于对象中的一个模块。我们通过模块化来管理整个对象。这就是面向对象编程。而在我们给别人使用这个对象的时候,只需要让别人实例化这个对象,然后就可以访问对象中的属性和对象中的方法了。
var person = {"name":"tom","age":"10"}
此处用json实现一个person对象,json对象是对象的一种字面量表示形式
function Person (name,age) {
this.name = name;
this.age = age;
}
var person = new Person('Tom',10); // 实例化对象
console.log(person.name); // 此处我们通过点语法来访问对象的属性
console.log(person.age);
function Person (name,age) {
this.name = name;
this.age = age;
}
Person.prototype = {
say:function() {
console.log(this.name + ' is saying');
}
}
var person = new Person('Tom',10);
person.say(); // Tom is saying
扩展知识:通常,我们都用此种方法来实例化对象,为了节省内存,我们把对象的方法都放在原型里面。为什么呢? 在我们通过new实例化对象的时候,在内存中,会自动拷贝构造函数中的所有属性和方法,用来给实例对象赋值,而不管我们实例化多少次,原型里面的属性和方法只生成一次,所以会节省内存。我们在实例化new的时候,系统做了如下几件事情:
console.log(person.__proto__ === Person.prototype); // true
另外,由此引出两个方法 hasOwnProperty() 和 isPrototypeOf()方法// 用三个if来 测试 hasOwnProperty
if(person.hasOwnProperty('name')){
console.log('name exsit'); // 输出 name exsit
}
if(person.hasOwnProperty('say')){
console.log('say exsit'); // 不输出
}
if(Person.prototype.hasOwnProperty('say')){
console.log('say exsit'); // 输出 say exsit
}
hasOwnProperty 此方法不会检查该对象的原型链,被检查的属性和方法必须是对象本身的一个成员。
// 先创建4个构造函数
function A() {}
function B() {}
function C() {}
function D() {}
B.prototype = new A(); // 把B的原型指向A实例化后的对象
C.prototype = new B(); // 把C的原型指向B实例化后的对象
D.prototype = new C(); // 把D的原型指向C实例化后的对象
// 下面开始来测试
var d = new D();
if (B.prototype.isPrototypeOf(d)) {
console.log('haha'); // 输出 haha
}
从这里可以看出 isPrototypeOf 和 instanceof 的区别,我们开始详细的说下:
function A() {}
function B() {}
function C() {}
function D() {}
B.prototype = new A(); // 把B的原型指向A实例化后的对象
C.prototype = new B(); // 把C的原型指向B实例化后的对象
D.prototype = new C(); // 把D的原型指向C实例化后的对象
var d = new D();
var c = new C();
var b = new B();
var a = new A();
console.log(A.prototype.isPrototypeOf(d)); // true 这里A是处于顶层,表示 A.prototype处于d的原型链上
console.log(B.prototype.isPrototypeOf(d)); // true
console.log(C.prototype.isPrototypeOf(d)); // true
console.log(D.prototype.isPrototypeOf(d)); // true
console.log(d instanceof C); // true
console.log(d instanceof B); // true
console.log(d instanceof A); // true
object instanceof AFunction 检测的是AFunction.prototype是否在object的原型链中,而不是检测AFunction自身。function Test(){
this.name = 'test';
this.test = function() {
console.log('test');
}
}
var str = 'javascript';
var json = {"name":"javascript"}
var fn = function() {}
扩展知识:函数声明和函数表达式的区别 函数声明会被提升,函数表达式不会被提升,请看下面代码:
function fn() {}
var func = function(){};
上面的代码实际解析的顺序是这样的:
var func;
function fn(){};
func = function(){};
有关提升的问题,请参考我之前的博文:http://blog.csdn.net/tyro_java/article/details/51131812
function Car(type,price) {
this.type = type; // 公有属性
this.price = price;
var private = 1; // private 是私有属性,外界或者原型里都无法访问,只在构造函数内部能访问
this.run = function() { // 对象方法
console.log('run');
}
}
Car.prototype = {
color:'black',// 原型属性
drive:function() { // 原型方法
console.log('drive');
},
test:function() {
console.log(private);
}
}
Car.Weight = 1000; // 公有静态属性,只能通过构造函数来访问,首字母一般大写
Car.Fly = function(){ // 类方法 ,只能通过构造函数来访问,首字母一般大写
console.log('car can\'t fly');
};
// 调用测试
var c = new Car('small',10000);
console.log(c.run()); // run
console.log(c.color); // black
console.log(Car.prototype.color); // black
console.log(c.drive()); // drive
console.log(Car.Weight); // 1000
console.log(Car.Fly()); // car can't fly
get,set取值器和设置器,用于对某一属性进行包装,用于取值和设置,js原生自带的两种。因为这个比较复杂我找到了一篇api文档,详细说明了这个,还有 Object.defineProperty() 方法的介绍。
function Classroom(id,num,teacher) {
this.id = id;
this.num = num;
this.teacher = teacher;
}
Classroom.prototype = {
property:{
blackbord:"only one",
chalk:"110pieces"
},
other:'hehe'
}
var cr = new Classroom(3,2,'Tom');
cr.property.blackbord = 'has two'; // 修改引用类型的property属性
cr.other = 'crhehe'; // 修改值类型的other属性
var cr2 = new Classroom(1,2,'Jack');
console.log(cr2.property.blackbord); // has two ,这里其它实例受到影响了
console.log(cr2.other); // hehe, 这里其它实例不受影响。
每个实例对象都有两个隐藏的属性一个是__proto__,一个是constructor。实例的__proto__属性来自它的构造函数,实例的constructor来自它的构造函数的原型里,下面用浏览器的 repl 环境下测试来验证这一说法,截图验证:
1.创建一个空的对象
2.拷贝构造函数中的属性和方法放到空对象里
3.自动生成一个__proto__属性指向类的原型
1.不管实例化多少次,原型对象只生成一次。
2.原型对象中的属性和方法可以被所有实例访问。
3.原型对象中引用类型的属性是共享的,值类型的属性是各自拥有的。
(在我之前的博文中有提到: http://blog.csdn.net/tyro_java/article/details/50990135 ,看实践二和实践三)
4.对象实例化后实际上生成了两个对象,一个是构造函数对象,一个是原型对象。
console.log(Object.constructor === Function); // true
console.log(Object.__proto__ === Function.prototype); // true
②不止是Object,在js中所有的内置对象都是Function的一个实例,如下所示:
console.log(String.constructor === Function); // true
console.log(String.__proto__ === Function.prototype); // true
console.log(Array.constructor === Function); // true
console.log(Array.__proto__ === Function.prototype); // true
console.log(Image.constructor === Function); // true
console.log(Image.__proto__ === Function.prototype); // true
// ... and so on
console.log(Number.__proto__ === Function.prototype); // true
console.log(Boolean.__proto__ === Function.prototype); // true
console.log(String.__proto__ === Function.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(Error.__proto__ === Function.prototype); // true
console.log(Date.__proto__ === Function.prototype); // true
console.log(Image.__proto__ === Function.prototype); // true
③ 而内置对象的实例,则各自指向各自的原型,如下所示:
var str = new String('hello');
var arr = new Array(1,2,3);
var img = new Image();
console.log(str.__proto__ === String.prototype); // true;
console.log(arr.__proto__ === Array.prototype); // true;
console.log(img.__proto__ === Image.prototype); // true;
④ 将随便挑一个比如String对象把它单独拿出来看,会有这么一条关系链,如下:
var str = new String('hello');
console.log(str.__proto__ === String.prototype); // true
console.log(String.prototype.__proto__ === Object.prototype); // true
console.log(String.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true
function A() {};
var a = new A();
console.log(a.__proto__ === A.prototype); // true
console.log(A.constructor === Function); // true
console.log(A.__proto__ === Function.prototype); // true
console.log(Function.constructor === Function); // true
console.log(Function.__proto__ === Function.prototype); // true
console.log(Function.prototype.__proto__ === Object.prototype); // true
console.log(A.prototype.__proto__ === Object.prototype); // true
console.log(Object.prototype.__proto__ === null); // true