js小记:对象、原型及原型链、面向对象编程

1、js对象

一、js对象 
js对象是一种复合数据类型,它能够把多个(不一样类型的)数据集中在一个变量中,而且给每一个数据起名字。javascript

二、对象与数组 
对象的每一个数据有对应的名字(属性名),咱们经过叫名字访问具体哪一个数据; 
数组的每一个数据没有名字,咱们只能经过编号来访问具体哪一个数据。 
从本质讲,数组就是对象的特殊形式,数组的每一个索引实质就是特殊化的 对象属性名。举个例子:php

var a = [0,1,2,3]; a['me'] = 1; a[-1] = '负数'; //负数 转换为 字符串 a[1.23] = '小数'; //小数 转换为 字符串 a['2.00'] = 'dad';//字符串 没法转换为 整数,因此仍为字符串 a['4'] = 'dad'; //字符串 转换为 整数 console.log(a); //[0, 1, 2, 3, "dad", me: 1, -1: "负数", 1.23: "小数", 2.00: "dad"] //由于 a['4'] = 'dad';,因此length值加1 console.log(a.length); //5 //上面例子说明数组的length属性,仅计算有 整数索引 的值的个数
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

三、建立对象的两种方式html

1)var o = new Object(); (2)var o = {}; (3)var o = new Object({x:0,y:0,radius:2}); (4)var ciclr = {x:0,y:0,radius:2};
  • 1
  • 2
  • 3
  • 4

对象 经过 构造器 生成:java

  • object(对象):下图左边的红圈(o、a、d···)
  • constructor(构造器):下图的右边的红圈(Object、Array···)

注:Object、Array等这些都是系统自带的构造器,咱们也能够自定义构造器(eg:下面深刻使用的 构造函数) 
这里写图片描述编程

并非全部函数都当构造器使用 
eg: var o = new Math.min();api

四、初始化/访问 数据数组

var book = new Object(); book.title = "math"; book.author = "bty"; book.chapter1 = { title:"math 简介", };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

五、删除对象属性浏览器

1)delete book.chapter1; //完全删除 (2)book.chapter1 = null; //仅仅置空
  • 1
  • 2

delete删除成功或删除的属性不存在返回true.闭包

  • 数组:delete后 不是完全删除,length不变
  • 对象:delete后 是 完全删除,没有length属性
//数组 var a = [0,1,1,2]; console.log(a.length);//4 delete a[1]; console.log(a.length);//4 console.log(a); //[0, empty, 1, 2] console.log(a[1]); //undefined //对象 var b = {aaa:1,bbb:2}; console.log(b); //{aaa: 1, bbb: 2} delete b['aaa']; console.log(b); //{bbb: 2} console.log(b.length); //undefined //说明对象没有length属性
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

六、遍历对象app

//key是obj里的属性名 for(var key in obj){ console.log(obj[key]); //console.log(obj.key);则会输出undefined }
  • 1
  • 2
  • 3
  • 4
  • 5

其次还有some(),every(),map(),forEach(),filter()等方法。 
具体用哪一个应场景而定。


2、相关知识

一、this

下面讲的仍是没这里好:Javascript中的this

(1)全局环境中的this: 
- 非严格模式:先指向undefined,而后再自动指向全局对象。 
- 严格模式:指向undefined 
如下均是 非严格模式。

例1:

//在浏览器中全局对象就是window。 var a = 10; alert(this.a); //10
  • 1
  • 2
  • 3

例2:

var a = 12; var obj = { a:1, b:this.a + 1 }; console.log(obj.b);//13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

特殊: 
new Function()里面的this,不论它是在构造函数中,仍是函数调用中, 
this都指向 全局对象。

(function(){ var f = new Function('alert(this)'); f(); })(); //或 function Foo(){ this.bar = function(){ var f = new Function('alert(this)'); f(); } } var foo = new Foo(); foo.bar();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

(2)构造函数中的this:指向新建立的对象(红圈部分) 
例1: 
这里写图片描述

例2:

var a = 1; var obj = { a:2, b:function(){ function fun(){ return this.a; } console.log(fun()); } }; obj.b();//1
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

(3)函数中的this:指向函数的调用者(红圈部分) 
这里的调用者就是建立的对象p1,输出:Hello,lily 
这里写图片描述

在例如

var a = 1; var obj = { a:2, b:function(){ return this.a; } }; //函数的调用者是obj console.log(obj.b());//2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

(4)eval()中的this:指向调用上下文中的this

//下面的闭包,这里的this指向的是Globel (function(){ eval('alert(this)'); })();
  • 1
  • 2
  • 3
  • 4
//这里的this是在bar函数里调用的,因此这里的this和bar函数里面的this同样。 //而bar函数里的this指向的是其调用者foo对象 function Foo(){ this.bar = function(){ eval('alert(this)'); } } var foo = new Foo(); foo.bar();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

 

二、apply、call

看下面场景:

function Point(x,y){ this.x = x; this.y = y; this.move = function(x,y){ this.x += x; this.y += y; } } var point = new Point(0,0); point.move(1,1);//移动到(1,1) var circle = {x:0, y:0, r:1}; //移动圆至(1,2) point.move.apply(circle,[1,1]); //或point.move.call(circle,1,1);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

咱们首先new了一个point对象,初始坐标(0,0),以后又将该点移动到(1,1)处。 
而后咱们又定义了circle对象,圆心坐标(0,0),变径1,以下图: 
这里写图片描述 
问题来了:如今咱们怎么经过Point的move方法来让 圆 移动到这个位置 
这里写图片描述 
经过下面两行任意一行代码便可: 
point.move.apply(circle,[1,1]); 
point.move.call(circle,1,1);

apply和call实际只是将 Point里的this指针的指向作了改变,point.move.call后,move方法开始指向circle对象。

call与apply区别: 
二者区别仅在参数上。apply第二个参数必须是个数组(把函数调用的值依次传入),而call把参数依次传入时用的不是数组,直接用逗号隔开而已,固然call第二个参数也能够是数组

三、原型与原型链
function Teacher(){ this.courses = [];//至关于私有变量 } Teacher.prototype = { //至关于public constructor:Teacher, job:'teacher', setName = function(name){ this.name = name; }, addCourse = function(course){ this.courses.push(course); } } var bill = new Teacher(); bill.setName('Bill'); bill.addCourse('math'); var tom = new Teacher(); tom.setName('Tom'); tom.addCourse('physics');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

上面代码原型链以下: 
bill和tom都有一个隐式指针_ proto_,都指向Teacher.proptotype。 
又由于Teacher是一个函数对象,而函数对象又是经过new Function()来创建的,Function也有一个protoptye。Function.prototype属性在js中是内置属性。 
Teacher的_ proto_是个对象,同理推之如图。

bill和tom是以Teacher.proptotype为原型,而Teacher.proptotype又以Object为原型。(这种原型继承的方式就叫原型链) 
这里写图片描述


原型链的操做

  • (1)属性查找
  • (2)属性修改
  • (3)属性删除

咱们继续用上面的例子 
(1)属性查找:

  • 访问tom.toString() 
    首先js先从tom中找toString方法,发现没有;而后再沿着原型链往上找,到Teacher.prototype中查找toString,发现也没有,而后再到object.prototype中查找,发现有,而后调用toString方法

(2)属性修改:

  • tom.name = ‘bty’; 
    首先js先在tom对象上查找有没有name属性,发现有,则直接将原来的’Tom’值改成’bty’。
  • tom.job = ‘assistant’; 
    首先js在tom对象上查找有没有job属性,发现没有,则直接在tom对象中添加job属性并赋值为’assistant’ 
    若想修改原型上的属性,则经过tom.prototype.job = 'assistant'修改,但这样会让全部Teacher建立出的对象job值都作修改。

(3)属性删除

  • delete tom.job; 
    假设tom.job = ‘assistant’已经执行。delete tom.job后会直接删除tom上的job属性,但不会删除原型上的job属性,此时再访问tom.job,值为teacher
  • delete tom.job; delete tom.job; 
    道理结果同上

判断对象是否有该属性: 
tom.hasOwnProperty(‘job’); 
请参考


原型的继承

原型的继承有两种方式:

  • 一、用构造器(具体参见 3、深刻使用)
  • 二、用Object.create(); (低版本的ie浏览器不兼容)

下面就详细说说Object.create(prototype, descriptors) 
详细参见此处

var teacher = { job:'teacher', courses:[], setName = function(name){ this.name = name; }, addCourse = function(course){ this.courses.push(course); } }; var bill = Object.create(teacher); bill.setName('Bill'); bill.addCourse('math');
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

var bill = Object.create(teacher)即建立一个以teacher对象为原型的bill对象。 
Object.create作的就是将bill的隐式指针_ proto_指向teacher,而不是指向teacher.prototype,这是一种新的原型继承的方式。以下图:

这里写图片描述


3、深刻使用

一、构造函数 
建立构造器的三种形式:

  • function Person(){}
  • var Person = function(){}
  • var Person = new Function();

例:

//为了和普通函数区分,构造函数首字母要大写 function Rect(w,h){ this.width = w;this.height = h; this.area = function(){return this.width * this.height}; } var r = new Rect(5,10); alert(r.area()); //50 //过程:new一个对象出来,而后将对象交给了Rect这个函数; //new出来的这个对象在Rect中就叫this //换句话说,this指向的是新建立的对象
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

至于为何不用下面代码,

function Rect(w,h){ this.area = function(){return w * h}; } var r = new Rect(5,10); alert(r.area()); //50
  • 1
  • 2
  • 3
  • 4
  • 5

是为了方便后续像r.width = 10;这样修改数值

注意:

function Person(name,age){ this.name = name; this.age = age; return {}; ///结尾加了个return {},此时new对象时就会返回空对象,因此下面打印undefined } var my = new Person('bty','12'); console.log(my.age); //undefined
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

二、原型对象 
(1)简单使用

function Person(){ Person.prototype.name = "Nicholas"; Person.prototype.age = 20; Person.prototype.sayName = function(){ alert(this.name); } } var person1 = new Person(); var person2 = new Person(); person1.sayName(); //Nicholas person2.sayName(); //Nicholas alert(person1.sayName === person2.sayName);//true person1.name = "Greg"; person1.sayName(); //sam//from instance person2.sayName(); //bty//from prototype
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

这里写图片描述
(2)原型的问题 
若是咱们对原型属性修改的是简单变量类型(eg:数值或字符串),ok,没问题。但若是修改是对象(eg:数组)就会出现问题。

function Person(){} Person.prototype = { //这些至关于 public 变量 constructor:Person, name:"bty", age:20, friends:["amy","sam"] }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("ssh"); alert(person1.friends);//amy,sam,ssh alert(person2.friends);//amy,sam,ssh 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

咱们发现对person1.friends进行操做,person2.friends也跟着改变。说明他们是共享friends的(public变量),如今咱们怎么将其变为 私有变量 呢?继续往下看。

三、组合原生和构造方法

function Person(name,age){ //这些是每一个对象拥有的属性,至关于 private 变量 this.name = name; this.age = age; this.friends = ['amy','sam']; } Person.prototype = { //这些至关于 public 变量 constructor:Person, sayName:function(){ alert(this.name); } }; var person1 = new Person("bty",20); var person2 = new Person("ssh",12); person1.friends.push('zsn'); alert(person1.friends); //amy,sam,zsn alert(person2.friends); //amy,sam alert(person1.friends === person2.friends); //false alert(person1.sayName === person2.sayName); //true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

4、全局对象(浏览器)

一、浏览器的全局对象是window 
二、浏览器中全部全局变量 实际就是 全局对象window的成员(属性)

var value = 12; alert(window.value);//12
  • 1
  • 2

三、window.document表示浏览器窗口中的HTML页面 
四、document.write()将内容写入html页面

for(x in window.document){ document.write(x) } //for(x in document){```}也行
  • 1
  • 2
  • 3
  • 4

5、面向对象编程

  • 全局变量
  • 封装
  • 继承
一、全局变量

定义方法: 
(1)在全局环境中 var a = ‘hhh’; 
(2)window.a = ‘hhh’; 
(3)(function(){ a = ‘hhh’})() //变量声明提高

注意:

//这里test为全局变量。a为局部变量 function todo(){ var a = test = 'hhh'; } //这里test2为全局变量,a二、b2为局部变量(注意看标点符号) function todo2(){ var a2 = 'hhh', b2 = 'hhh'; test2 = 'hhh2'; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
二、封装

经过prototype封装public变量;经过直接在Aaa上声明,封装私有变量,而后咱们经过添加 this.XXX 方法,来访问私有变量。

function Aaa(){ //至关于私有属性 var _config = ['A','B','C']; this.getConfig = function(){ return _config; } } //至关于公有属性 Aaa.prototype = { _step1:function(){}, _step2:function(){}, api:function(){} }; var my = new Aaa(); //外部没法访问config,必须经过this.XXX 方法以相似API的形式才能访问config console.log(my.config);//undefined console.log(my.getConfig());//["A", "B", "C"]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
三、继承
  • 原型继承(JS固有的继承) 
    -原型的继承又两种方式:Object.create()和构造器
  • 类继承(模拟C、JAVA的继承)

(1) 类继承(模拟C、JAVA的继承) 
咱们如今模拟:B继承A

//(function(){})()是个闭包 (function(){ function ClassA(){ var classMethod = function(){}; } ClassA.prototype = { api:function(){} }; function ClassB(){ ClassA.apply(this,arguments); } ClassB.prototype = new ClassA(); ClassB.prototype = { constructor:ClassB,//由于以前constructor是ClassA,因此要改为B api:function(){ ClassA.prototype.api.apply(this,arguments); } }; var b = new ClassB(); b.api(); })()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

这里写图片描述

(2)原型继承(JS固有的继承)

// (function(){ var myproto = { action1:function(){}, action2:function(){}, }; //obj的隐式指针_ proto_直接指向了myproto var obj = Object.create(myproto); })();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

因为IE低版本浏览器不支持Object.create(),因此咱们能够写个函数模拟下,以下:

var clone = (function(){ var F = function(){}; return function(proto){ F.prototype = proto; return new F(); } })();
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

解释:咱们建立函数F,再为其指定原型,而F的原型就是传入的proto对象的原型。最后在new F(),即最后建立了个新的对象,而这个对象是以F.proto为原型,即以传入对象proto为原型

相关文章
相关标签/搜索