2018-11-22 面向对象3
JavaScript的面向对象是基于constructor(构造函数)与prototype(原型链)的。
1.构造函数:constructor
构造函数就是一个函数。和普通函数有一些区别:
- 函数的内部使用this的关键字。
- 首字母是大写的。
- 使用的时候要用new操作符创建实例对象。
2.原型:prototype
原型是一个对象,称为原型对象。
构造函数创建实例对象,构造函数具有原型,实例对象也具有原型。实例对象的原型指向构造函数的原型。这就是原型链。
3.原型链:
4.proto:每一个实例对象都具有的私有属性。指向自己的原型。
proto属性(前后各两个下划线),用来读取或设置当前对象的prototype对象。目前,所有浏览器(包括 IE11)都部署了这个属性。
eg:1__protp___
效果如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
let a = new Array();
console.log(a);
function A(){
this.a = '1';
}
let b = new A();
console.log(b.__proto__)
console.log(A)
</script>
</html>
constructor: 构造器。指向自己的构造函数。
5.new :
创建对象实例。
防止漏掉new造成错误:
在构造函数内部使用严格模式。
使用instanceof在内部判断。判断是否为当前对象的实例。
使用new.target 在内部判断,new.target指向自己的构造函数。
eg:2new
效果如下:
22.new1.jpg 22.new1.1.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
ll = 'lala';
function A(name){
console.log(this); //此处的this指代的是全局作用域window
this.ll = name;
function ss(){
alert(this.ll);
}
}
A.prototype.say = function(){
alert(this.ll);
}
/*
let a = new A ('zhangsan');
a.say(); //页面弹出“zhangsan”的字样打印A{}的数组
*/
let a = A('lili');
console.log(ll) //页面打印window的全局作用域 、 lili
</script>
</html>
eg:3new
效果如下:
22.new2.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
function A (name){
'use strict'; //严格模式
this.name = name;
}
let a = new A('lisi');
//递归
function B(name){
// this指向新创建的实例
if(!(this instanceof B)){
return new B(name);
}
this.name = name;
}
let b = new B('lili');
console.log(b.name);
let bb = B ('sisi');
console.log(bb.name);
//new.target指向自己的构造函数
function V (name){
if(!(new.target == V)){
throw new Error('这个对象必须使用new来创建对象');
}
this.name = name;
}
let v = new V('kk');
let vv = V('kk');
</script>
</html>
6.new的深入操作:
1.创建一个空对象,作为将要返回的对象实例。
2.将这个空对象的原型,指向构造函数的prototype属性。
3.将这个空对象赋值给函数内部的this关键字。
4.开始执行构造函数内部的代码。
5.将对象实例返回
eg:4new
效果如下:
22.new3.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
function A(name){
this.name = name;
return 123; //简单数据类型
}
let a = new A('123');
console.log(a); //打印出的是A数组里面的内容
function B(name){
this.name = name;
return this;
}
let b = new B('123645');
console.log(b); //打印出的是B数组里面的内容
function C(name){
this.name = name;
return {
name:'zhangsan'
};
}
let c = new C('1689156');
console.log(c); //打印出的是C数组里面的内容
</script>
</html>
7.构造函数里面的return语句:
如果return的是普通数据类型。那么相当于没写。
如果返回的是this,那么返回的与本身返回的是一样的。
如果返回的是一个其他对象。那么结果返回的就是这个对象。所以在构造函数内部返回对象要小心。
8.任何一个函数都可以使用new。返回值都是一个对象。
如果这个函数是一个构造函数的话,返回的是这个函数的实例。
如果函数是一个普通函数,那么返回的是一个空的对象。
9.Object对象,是所有JS对象的基础。
Object 的原型指向null。一切对象的基础是null,null也叫空。
eg: 5 Object
效果如下:
22.5Object.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
console.log(Object.prototype.__proto__); //打印得null说明打印出的是对象原型是空
</script>
</html>
9.(1)Object.create();
有的时候我们拿不到对象的构造函数。可以根据这个对象的某一个实例去创建一个对象。
eg:6create
效果如下:
22.6create.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
function A(name){
this.name = name;
}
let a = new A('LILI');
let b = Object.create(a); //有的时候我们拿不到对象的构造函数。可以根据这个对象的某一个实例去创建一个对象。
console.log(b); //A name: "zhangsan"__proto__: A 此处获取的是b.name的命名'zhangsan'
b.name = 'zhangsan';
console.log(a.name); //LILI 此处获取的是a中为A创建的一个实例'LILI'
</script>
</html>
对于对象来说,每一个属性 其实都有四个描述。
value 值
enumerable 枚举 遍历 for in
configurable 修改
writable 删除
后面三个默认值都是true。
eg:7create
效果如下:
22.7create.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
let obj = new Object();
//添加属性
obj.p1 = 'lili';
obj.p2 = 16;
let obj2 = Object.create(obj,{ //有的时候我们拿不到对象的构造函数。可以根据这个对象的某一个实例去创建一个对象。(后面三个默认值都是true。)
/*value:值
enumerable:true,
configurable:true,
writable:true
*/
p1:{
value:'llaaa',
enumerable:false, //*
},
p2:{
value:56,
enumerable:true,
configurable:true,
writable:true,
}
});
for(let i in obj){ //让i拥有obj的值
console.log(i,obj2[i]); //打印出p1 llaaa, p2 56
}
</script>
</html>
eg:8.enumerable
效果如下:
22.8enumerable.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
var obj = {
a:'a',
b:'b',
c:'c',
};
for(let i in obj){ //让i拥有obj的值
console.log(i,obj[i]);
}
console.log('___________________________')
Object.defineProperty(obj,'c',{
value:13,
//可枚举性(enumerable)用来控制所描述的属性,是否将被包括在for...in循环之中。一般enumerable后面跟的值true
enumerable:false,
});
for(let i in obj){
console.log(i,obj[i]);
}
</script>
</html>
9.(2)Object.getPrototypeOf(obj)
获取obj对象实例的原型
eg:9Object.getPrototypeOf
效果如下:
22.9getprototypeof.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
function A(name){
this.name = name;
}
let a = new A('lili');
console.log(Object.getPrototypeOf(a)); //获取对象原型
console.log(a.__proto__)
Object.getPrototypeOf({}) === Object.prototype //true
//new Object 与Object的原型是一致的。对象的原型与构造函数的原型是一致的。
Object.getPrototypeOf({})===null
//Object对象的原型的原型指向null。null也是原型链的顶点。
function f(){}
Object.getPrototypeOf(f)===Function.prototype //true
//构造函数的原型与内置对象function的原型相同。f=== new Function();
</script>
</html>
9.(3)Object.prototype.isPrototypeOf() 判断该对象是否为参数对象的原型
eg:console.log(Array.prototype.isPrototypeOf(b));
obj1.isPrototypeOf(obj2)
判断obj2的原型是否是obj1。
9.(4)Object.setPrototypeOf(obj)设置obj对象实例的原型
eg:10setPrototypeOf
效果如下:
22.10Object.setPrototypeOf.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
let a = new Array();
//Object.getPrototypeOf(obj)获取obj对象实例的原型
console.log(Object.getPrototypeOf(a));
//Object.setPrototypeOf(obj)设置obj对象实例的原型
Object.setPrototypeOf(a,Number.prototype);
console.log(Object.getPrototypeOf(a));
</script>
</html>
9.(5)Object.getOwnPropertyNames() 成员是参数对象本身的所有属性的键名,不包含继承的属性键名。
eg:12Object.getOwnPropertyNames()
效果如下:
22.12Object.getOwnPropertyNames().jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
function A(name){
this.name=name;
this.say = function(){
console.log(a);
}
}
A.prototype.ss = function(){
console.log('ss');
}
function B(name){
A.call(this);
this.age = 16,
this.sex = 'man'
};
for(let i in A.prototype){
B.prototype[i] = A.prototype[i];
}
let b = new B ('lala');
b.ss();
//Object.getOwnPropertyNames() 成员是参数对象本身的所有属性的键名,不包含继承的属性键名。
console.log(B.prototype.hasOwnProperty('say')); //ss false
</script>
</html>
9.(6)Object.prototype.hasOwnProperty() 用于判断某个属性定义在对象自身,还是定义在原型链上。
10.函数属性的区别:
- 私有属性 : 在对象的定义中定义的非全局变量(在对象的定义中定义的非全局变量这种方式定义的属性,类的实例不能访问;只能通过 类名.属性名访问)
- 实例属性 : 使用this为对象附加实例属性/对象名称.属性名(这种方式定义的属性,只能通过类的实例访问.不同实例之间共享该属性;不能通过 类名.属性名的方式访问)
-
类属性 : "类"名.属性名/类名.prototype.属性名
eg:13私有属性与实例属性
效果如下:
22.13私有属性.jpg
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
function F(name){
A.call(this);
B.call(this); //此处的A.call 与B.call是属于实例函数 这种方式定义的属性,只能通过类的实例访问.不同实例之间共享该属性;不能通过 类名.属性名的方式访问
let ll = name ; //私有成员 此处的‘ll’是私有属性私有属性 在对象的定义中定义的非全局变量这种方式定义的属性,类的实例不能访问;只能通过 类名.属性名访问
this.getName = function(){
console.log(ll);
}
}
let f = new F('lili');
f.getName();
</script>
</html>
11.命名空间
eg:14命名空间
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
</body>
<script>
//适用于大型项目组
//在所有的调用函数前设置一个qq的命名,让所有的要调用的函数都包含在qq中以避免与项目组的成员之间的项目函数调用重名
var qq= {
this.F = function(){
}
this.S = function(){
}
};
li.F()
</script>
</html>