文章目录
1.概述
面向对象:对代码的一种抽象,对外统一提供调用接口的编程思想。
2.名词解释
属性:事物的特性
方法:事物的功能
对象:事物的一个实例
原型:JS函数中有prototype属性引用了一个对象,即原型对象(原型),每个函数都有prototype属性,prototype属性所引用的值也是一个对象(Object),它的作用是定义所有对象实例所共享的属性和方法。prototype,对于构造函数来说,它是一个属性;对于对象实例来说,它是一个原型对象。
使用prototype:
function Person(name,height){
this.name=name;
this.height=height;
}
Person.prototype.hobby=function(){
return 'watching movies';
}
var boy=new Person('keith',180);
var girl=new Person('rascal',153);
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby); //true
此时,若改变prototype上hobby方法的内容,所有Person对象的实例中hobby方法都会跟着改变,除非该对象显式地重新定义了该方法。(优先查找实例方法,若不存在则查找原型对象上的方法。)
不使用prototype:
function Person(name,height){
this.name=name;
this.height=height;
this.hobby=function(){
return 'watching movies';
}
}
var boy=new Person('keith',180);
var girl=new Person('rascal',153);
console.log(boy.name); //'keith'
console.log(girl.name); //'rascal'
console.log(boy.hobby===girl.hobby); //false
闭包:
闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数)。闭包的本质就是在一个函数内部创建另一个函数。
全局变量可以在函数内部直接访问,而不需要通过传参访问。但反过来,在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的。想在一个函数内部也有限权访问另一个函数内部的变量,就要用到闭包。
闭包的3个特性:
①函数嵌套函数
②函数内部可以引用函数外部的参数和变量
③参数和变量不会被垃圾回收机制回收
函数作为返回值:
例1:
function a(){
var name = 'zijeak';
return function(){
return name;
};
}
b = a();
b();
打印结果为:zijeak
例2:
function a(){
var i=0;
function b(){
alert(++i);
}
return b;
}
var c = a();
c();
打印结果为1
例3:
function fn(){
var num = 3;
return function(){
var n = 0;
console.log(++n);
console.log(++num);
}
}
var fn1 = fn();
fn1();// 1 4
fn1();// 1 5
匿名函数作为返回值,在fn函数调用后返回给fn1,但因为匿名函数内部引用了num,导致其不能随fn调用的结束而销毁,因此num会一直保留在内存中,可以被访问。
闭包的优缺点:
好处
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)
③匿名自执行函数可以减少内存消耗
坏处
①被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响
3.声明对象
3.1 JS字面式声明对象
var person = {
name:'Zhangsan',
age:26,
sex:"male",
eat:function(food){
alert(this.name+" is eating "+food);
}
}
person.eat("shit");
3.2 new操作符
person = new Object();
person.name = 'Zhangsan';
person.age = 26;
person.eat = function(food){
alert(this.name+" is eating "+food);
}
person.eat("apple");
添加构造函数之后:
function Person(name,sex,age){
this.name = name;
this.sex = sex;
this.age = age;
this.eat = function(food){
alert(this.name+" is eating "+food);
}
}
var person = new Person('Zhangsan',26,'male');
person.eat('banana');
3.3 JS中工厂方式声明对象
function createPerson(name,sex,age){
var person = new Object();
person.name = name;
person.sex = sex;
person.age = age;
person.eat = function(food){
alert(this.name+" is eating "+food);
}
return person;
}
var person = createPerson('Zhangsan',26,'male');
person.eat('Pear');
3.4 JS中原型模式声明对象
原型模式的根本:函数本身声明为空内容,利用prototype定义一些属性及方法。
好处:让所有实例化的对象都拥有它包含的属性及方法。
定义方式一:
function test(){
}
test.prototype.color = 'red';
test.prototype.height = '1.7';
test.prototype.width = '1.2';
test.prototype.showInfo = function(){
alert(this.color+"---"+this.height+"---"+this.width);
}
var car = new test();
car.showInfo();
定义方式二:JSON数据定义属性和方法
function test(){
}
test.prototype={
color:'red',
height:'1.7',
width:'1.2',
showInfo:function(){
alert(this.color+"---"+this.height+"---"+this.width);
}
}
var car = new test();
car.showInfo();
3.5 JS中混合模式声明对象
function test(color,height,width){
this.color = color;
this.height = height;
this.width = width;
}
test.prototype={
showInfo:function(){
alert(this.color+"---"+this.height+"---"+this.width);
}
}
var car = new test('red','1.7','1.2');
car.showInfo();
4.遍历对象的属性
对象可以当做数组处理,使用for-in循环遍历
//声明
function test(color,height,width){
this.color = color;
this.height = height;
this.width = width;
}
test.prototype={
showInfo:function(){
alert(this.color+"---"+this.height+"---"+this.width);
}
}
var car = new test('red','1.7','1.2');
//遍历
for(var i in car){
console.log(i);//取属性或方法的名称
console.log(car[i]);//取属性的值或方法的代码
}
对象在内存中的分布
索引(地址)存在栈内存
属性和方法名存在堆内存
方法体存在代码段
5.封装
封装(Encapsulation):把对象内部数据和操作细节进行隐藏。Javascript可以通过闭包实现封装。
function demo(){
var num = 1;
function get_num(){//特权方法
return num;
}
return get_num;
}
var use_demo = demo();
alert(use_demo());
function demo(){
function _num(){
alert("num");
}
this.num = function(){
return _num;
}
}
var use_demo = new demo();
var a = use_demo.num();
a();
use_demo._num();//错误
6.原型和原型链
原型:是利用prototype添加属性和方法
原型链:JS在创建对象(不论是普通对象还是函数对象)的时候,都有一个叫做__proto__
的内置属性,用于指向创建它的函数对象的原型对象prototype
。
var person = function(){};
var p = new person();
第一步:var p={}
创建对象
第二步:p.__proto__ = person.prototype
第三步:创建对象(初始化对象)p person.call(p)
例如:
var person = function(){}
person.prototype.say=function(){
alert("天气挺好");
}
var p = new person();
p.say();
这里的p没有say方法,因此会在p.__proto__
中查找,而p.__proto__ = person.prototype
,person.prototype
有say方法。
这就说明了,函数对象内有一个隐含属性__proto__
,其指向创建该对象的函数对象的原型对象prototype
var person = function(){};
person.prototype.say = function(){
alert("天气挺好");
}
person.prototype.gongzi = 500;
var programmer = function(){};
programmer.prototype = new person();
programmer.prototype.wcd = function(){
alert("明天天气也不错");
}
programmer.prototype.gongzi=1000;
var p = new programmer();
//p.say(); //可以调用
//p.wcd();
alert(p.gongzi);
// var p = new programmer(); p.__proto__ = programmer.prototype = new person();
//var p1 = new person(); programmer.prototype = p1
// p.say(); p.__proto__ --> programmer.prototype ==p1 --->p1.__proto__ ==person.prototype.say();
//原型链实现过程 ***
继承
JS中的继承实质上是利用原型链,在实例化子类对象时使用父类构造方法进行实例化。
//父类
function person(name,age){
this.name = name;
this.age = age;
}
person.prototype.sayHello = function(){
alert("hello");
}
//子类
function student(){};
student.prototype = new person('zijeak',20);
student.prototype.grade = 3;
student.prototype.test = function(){
alert(this.grade);
}
var s = new student();
s.sayHello();
构造继承
在子类内部构造父类的对象实现继承
使用call和apply继承
call
:调动一个对象的一个方法,以另一个对象替换当前对象。
apply
:应用某一对象的一个方法,用另一个对象替换当前对象。
7.关键词
instanceof
:判断一个变量是否是一个对象的实例
var arr = new Array();
alert(arr instanceof Array);
delete
:用于删除对象的属性,不能用于删除方法
delete obj.name;
call
和apply
:用于用来重定义 this 这个对象。
callee
:返回正在执行的function对象,callee是agruments的一个属性。callee实际上指代函数本身,内容为函数内容。
如果当做属性调用,返回函数内容:arguments.callee
如果当做函数调用,意为在函数内部再次调用本函数,若无退出条件,会发生死循环:arguments.callee()
arguments
:js中每个函数都有一个Arguments对象的实例,引用函数的参数(实参),可以用数组下标的方式引用arguments元素,它有length属性,callee属性引用函数自身。
this
:
this可以在函数内部定义属性/变量(定义出来的是全局变量)
this作为方法调用,构造函数内部this指向当前对象。
function test(){
this.name="zs";
}
this是call、apply的第一个参数
8.对象冒充
将父类的属性和方法一起传给子类作为特权属性和特权方法