一、js对象

1、js对象 
js对象是一种复合数据类型,它可以把多个(不同类型的)数据集中在一个变量中,并且给每个数据起名字。

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

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

3、创建对象的两种方式

(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

对象 通过 构造器 生成:

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

注:Object、Array等这些都是系统自带的构造器,我们也可以自定义构造器(eg:下面深入使用的 构造函数) 

并不是所有函数都当构造器使用 
eg: var o = new Math.min();

4、初始化/访问 数据

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

5、删除对象属性

(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

6、遍历对象

//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()等方法。 
具体用哪个应场景而定。


二、相关知识

1、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
2、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第二个参数也可以是数组

3、原型与原型链
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’); 
请参考


原型的继承

原型的继承有两种方式:

  • 1、用构造器(具体参见 三、深入使用)
  • 2、用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,这是一种新的原型继承的方式。如下图:


三、深入使用

1、构造函数 
创建构造器的三种形式:

  • 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

2、原型对象 
(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变量),现在我们怎么将其变为 私有变量 呢?继续往下看。

3、组合原生和构造方法

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

四、全局对象(浏览器)

1、浏览器的全局对象是window 
2、浏览器中所有全局变量 实际就是 全局对象window的成员(属性)

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

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

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

五、面向对象编程

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

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

注意:

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

通过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
3、继承
  • 原型继承(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为原型

js小记:对象、原型及原型链、面向对象编程的更多相关文章

  1. js 继承 对象方法与原型方法

    js函数式编程确实比很多强语言使用灵活得多,今天抽了点时间玩下类与对象方法调用优先级别,顺便回顾下继承 暂时把原型引用写成继承 先看看简单的两个继承 var Parent = function(){} ...

  2. 【JS】#001 JS定义对象写法(原型、JSON方式)

    下面主要写两种 JS 定义对象的 常用写法 写法1:[很像面向对象语言中的写法] function zhongxia(age) { this.age = age; } zhongxia.name = ...

  3. jQuery编程基础精华01(jQuery简介,顶级对象$,jQuery对象、Dom对象,链式编程,选择器)

    jQuery简介 什么是jQuery? jQuery就是一个JavaScript函数库,没什么特别的.(开源)联想SQLHelper类 jQuery能做什么?jQuery是做什么的? jQuery本身 ...

  4. javaScript设计模式之面向对象编程(object-oriented programming,OOP)(二)

    接上一篇 面向对象编程的理解? 答:面向对象编程,就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法).这个对象我们称之为类.面向对象编程思想其中一个特点就是封装,就是把你需 ...

  5. JavaScript高程第三版笔记-面向对象编程

    之前有篇博客曾提到过一点js的面向对象编程:js面向对象编程. 这里就结合js高程详细剖析一下javascript的面向对象编程. 前序: 1⃣️Object.defineProperty() var ...

  6. Javascript面向对象编程(一)

    什么是面向对象? 它是一种新的编程模式.以往的面向过程是将功能都写在一起,逐行实现.面向对象与其不同,它只关心对象提供的功能,而不在乎细节. 面向对象的特点? 抽象:抓住问题的核心,贯穿始终: 封装: ...

  7. JavaScript系列:模块化与链式编程

    模块化:闭包和和函数作用域(JS没有块级作用域ES6之前)构造模块 var man=function(){ var age=12; return { getYear:function(){ retur ...

  8. Python之路【第五篇】:面向对象编程

    面向对象编程思维导向图

  9. Python 第六篇(上):面向对象编程初级篇

    面向:过程.函数.对象: 面向过程:根据业务逻辑从上到下写垒代码! 面向过程的编程弊:每次调用的时候都的重写,代码特别长,代码重用性没有,每次增加新功能所有的代码都的修改!那有什么办法解决上面出现的弊 ...

  10. jQuery链式编程

    链式编程 多行代码合并成一行代码,前提要认清此行代码返回的是不是对象.是对象才能进行链式编程 .html(‘val’).text(‘val’).css()链式编程,隐式迭代 链式编程注意:$(‘div ...

随机推荐

  1. 使用 python 管理 mysql 开发工具箱 - 2

    这篇博文接着上篇文章<使用 python 管理 mysql 开发工具箱 - 1>,继续写下自己学习 python 管理 MySQL 中的知识记录. 一.MySQL 的读写分离 学习完 My ...

  2. php PDO操作类

    <?php /*//pdo连接信息 $pdo=array("mysql:host=localhost;dbname=demo;charset=utf8","root ...

  3. laravel5.6 调用第三方类库

    大概流程: 1. 新建一个目录方类库 2. 配置composer配置文件 3. 在项目中使用终端运行composer  dumpautoload 4. 使用时 方法调用可以new对象后->方法名 ...

  4. 解决 Package test is missing dependencies for the following libraries: libcrypto.so.1.0.0

    根据项目要求需要用到openssl这个库,看了看编译环境幸好本身就集成了该库.但在编译openssl的功能时,碰到缺少类库的错误. Package test is missing dependenci ...

  5. Java多线程 -join用法

    阿里面试官问我这个问题,我仔细总结了一下: 参考:sleep.yield.wait.join的区别(阿里面试) 1. join()介绍 join() 定义在Thread.java中.join() 的作 ...

  6. java finally 与return

    finally之外的语句块有return,finally语句块没有return:该语句块的返回值被固定下来,等fianlly执行完后返回给调用者 finally语句块与其他语句块同时有return:返 ...

  7. C++解析(10):struct和class的区别

    0.目录 1.默认访问级别 2.默认继承方式 2.1 分别独立继承 2.2 struct继承class 2.3 class继承struct 3.小结 1.默认访问级别 在用struct定义类时,所有成 ...

  8. BZOJ4197 [Noi2015]寿司晚宴 【状压dp】

    题目链接 BZOJ4197 题解 两个人选的数都互质,意味着两个人选择了没有交集的质因子集合 容易想到将两个人所选的质因子集合作为状态\(dp\) \(n\)以内质数很多,但容易发现\(\sqrt{n ...

  9. linux设置开机自动启动

    有很多中方法,这里只取最简单的一种: 把启动命令放到/etc/rc.d/rc.local文件里这样就可以每次启动的时候自动启动服务了, 注意给rc.local执行权限

  10. 常用Actoin算子 与 内存管理 、共享变量、内存机制

    一.常用Actoin算子 (reduce .collect .count .take .saveAsTextFile . countByKey .foreach ) collect:从集群中将所有的计 ...