目录
2,构造函数原型prototype的__proto__指向Object.prototype
3,Object对象的原型对象的__proto__属性指向null
4,普通函数的__proto__指向Function.prototype
八,原型对象的constructor属性指向该原型的构造函数
1,Object.getPrototypeOf()获取对象原型
2,Object.setPrototypeOf()将一个对象设为另一个对象的原型
4,Object.getOwnPropertyNames()返回一个对象所有的属性数组
5,Object.hasOwnPropertyNames()判断一属性是否属于对象自身
2,使用Object对象create,setPrototypeOf方法实现继承
一,理解类、对象、面向对象编程
生活中的所有人都是共性和个性的矛盾体,每个人在具有共性的基础上又具有个性。每个人都会说话就是共性,但是每个人的声音不同就是个性。把具体的人看作人这个类的对象,所以对象就是共性+个性。
编程中,对象由类构造得到,这个类的所有对象具有相同的基础(相同的基础指的是所有对象都具有相同的属性和方法)。
但是每个对象还具有自己特殊的特点(每个对象的属性值和方法结果各不相同)。
面向对象编程OOP是一种编程思维,面向过程与面向对象不可分离。面向对象的最大特点就是代码复用,一些共性代码我们没有必要再写,而是直接使用,在共性的基础再添加个性。
二,声明一个类——构造函数
在ES5,js使用构造函数作为类的概念,所有实例对象(instance)都是从构造函数得到。我们常见的Array()就是构造数组实例对象的构造函数。构造函数中一般写属性和方法,原型中一般写方法。
构造函数的两个特点:1,函数名首字母必须大写;2,必须使用new关键字生成实例。
下面是声明一个构造函数的语法:
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(`${this.name}说你好`);
}
}
xiaoming = new Person('xiaomng', 18);
xiaoming.say()
xh = new Person('xh', 18);
xh.say()
这种方法与使用运算符{}得到的字面量对象在语法实现上不同,字面量对象由Object()构造函数得到。
三,prototype原型
一般说原型指的是构造函数的原型,比如Array.prototype,表面上他是Array类的属性,但是这个属性指向的是一个对象,也就是说Array.prototype是一个对象。
任何函数(普通函数,构造函数,对象方法)都具有prototype属性。普通函数和对象方法的prototype属性指向一个Object空对象,即{}。构造函数的原型也是一个Object对象但不是空的。
new关键字实现了实例对象拥有构造函数的的基础属性和原型属性,
1,为什么需要原型prototype?
一方面是节省内存空间,另一个当面是实现继承。
function Person(name, age) {
this.name = name;
this.age = age;
this.say = function() {
console.log(`${this.name}说你好`);
}
}
xiaoming = new Person('xiaomng', 18);
xh = new Person('xh', 18);
console.log(xiaoming.say === xh.say);// false
/*
false说明xiaoming对象和xh对象的say方法占据的是不同的内存空间,假如Person类具有
很多的instance,则会将内存用完。有没有一种方法让 xiaoming.say === xh.say 为true呢?
答案是使用原型prototype
*/
2,在一个构造函数的原型中添加属性和方法
在原型中添加的属性和方法,会被这个构造函数所有的实例对象所共享。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function() {
console.log(`${this.name}说你好`);
}
Person.prototype.grade = '高三';
xiaoming = new Person('xiaomng', 18);
xh = new Person('xh', 16);
xiaoming.say();
xh.say();
// xiaomng说你好
// xh说你好
console.log(xh.grade, xiaoming.grade);
// 高三 高三
console.log(xiaoming.say === xh.say);
//true,说明是同一块内存空间
四,给构造函数添加静态属性和静态方法
js是一门动态语言,可以运行过程中给类添加方法和属性。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.nation = 'china';
Person.speak = function() {
console.log('说普通话');
}
Person.speak();
console.log(Person.nation);
五,给实例对象instance添加实例属性和实例方法
js是一门动态语言,可以运行过程中给实例对象添加方法和属性。
function Person(name, age) {
this.name = name;
this.age = age;
}
xh = new Person('xh', 16);
xh.grade = '高一';
xh.run = function() {
console.log('慢慢的跑');
}
console.log(xh.grade);
xh.run()
// 高一
// 慢慢的跑
六,构造函数的原型与实例对象自身属性与方法同名
js引擎会优先在实例对象本身的属性中寻找相关的属性和方法,如果在对象本身没有找到,则去他的构造函数里面寻找相关的属性和方法。如果存在同名的情况,则会使用对象本身的属性和方法。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.grade = '高三';
Person.prototype.run = function() {
console.log('用脚走路');
}
xh = new Person('xh', 16);
xh.grade = '高一';
xh.run = function() {
console.log('羞答答的走');
}
console.log(xh.grade);
xh.run();
// 高一
// 羞答答的走
七,实例对象的__proto__属性
任何对象都具有__proto__属性。构造函数的实例对象的__proto__属性指向其构造函数的原型,函数对象的__proto__属性指向Function构造函数的原型,字面量对象的__proto__指向Object的原型,数组对象的__proto__指向Array()的原型,构造函数的原型指向一个Object空对象,即{}。原型对象的__proto__指向Object.prototype。
1,__proto__属性指向谁?
由构造函数创建得到的实例对象都具有__proto__这个属性,它指向他的构造函数的原型对象。
function Person(name, age) {
this.name = name;
this.age = age;
}
xh = new Person('xh', 16);
console.log(xh.__proto__ === Person.prototype);
// true
2,构造函数原型prototype的__proto__指向Object.prototype
因为任何构造函数的原型对象都是由Object所创建,所以任何构造函数的原型对象的__proto__属性都指向Object对象的原型Object.prototype。
3,Object对象的原型对象的__proto__属性指向null
由于Object对象是js中的最高级别对象,他没有构造函数,所以他的__proto__属性指向null。
4,普通函数的__proto__指向Function.prototype
普通函数由Function类创建。
八,原型对象的constructor属性指向该原型的构造函数
任何构造函数的原型对象都具有constructor属性,它指向该原型的构造函数。
我们使用构造函数的prototype属性找到该构造函数的原型,那么该怎么从原型找到他本身的构造函数呢?
使用原型对象的constructor属性找到原型对象本身的构造函数。
九,由__proto__属性构成的原型链
1,什么是原型链?
js中任意对象都具有原型,而原型也是对象,那么原型也有原型,原型的原型也有原型……如此套娃就形成了原型链,prototype chain。
js通过原型链实现了继承。
2,一张图看懂原型链
十,instanceof运算符
instanceof运算符根据原型链判断某个实例对象是否为一个构造函数的实例。
function Person(name, age) {
this.name = name;
this.age = age;
}
xh = new Person('xh', 16);
console.log(xh instanceof Person);
console.log(xh instanceof Object);
// true
// true
十一,Object对象的相关方法
1,Object.getPrototypeOf()获取对象原型
ObjectgetPrototypeof方法返回参数对象的原型。这是获取原型对象的标准方法。
var arr = [];
console.log(object.getPrototypeof(arr));
2,Object.setPrototypeOf()将一个对象设为另一个对象的原型
Object.setPrototypeOf方法为参数对象设置原型,返回该参数对象。它接受两个参数,第一个是现有对象,第二个是原型对象。
var arr = {};
var job = { teacher: "xh" };
Object.setPrototypeOf(arr, job);
console.log(arr.teacher);
3,Object.create()方法实现实时动态继承
3.1 单参数实现复用别的代码
var arr = {};
var job = { teacher: "xh", };
arr = Object.create(job);
console.log(arr.teacher);
job['run'] = function() { console.log('runing'); }
arr.run()
// xh
// runing
3.2 双参数实现既复用又新添加
var job = { teacher: "xh", };
var obj = Object.create(job, {
salary: { value: '10000' },
addr:{value:'beijing'}
});
console.log(obj.teacher);
console.log(obj.infom);
4,Object.getOwnPropertyNames()返回一个对象所有的属性数组
Object.getOwnPropertyNames方法返回一个数组,成员是参数对象本身的所有属性的键名,不包含继承的属性键名。
console.log(Object.getOwnPropertyNames(Array));
5,Object.hasOwnPropertyNames()判断一属性是否属于对象自身
Date.hasownProperty('length');// true
Date.hasownProperty('tostring');//false
十二,js对象的继承
js通过原型对象实现继承。如果出现属性和方法重名,则按就近原则去寻找。
1,继承的一般写法
//构造函数继承,先继承父类的基础属性,在通过遍历原型对象继承父类原型
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.getName = function() {
console.log(this.name);
}
Person.prototype.getAge = function() {
console.log(this.age);
}
function Student(learn, name, age) {
//基础属性:调用父类的构造函数,将Student实例对象的this传进父类,父类的this就指向Student实例对象
Person.call(this, name, age);
this.learn = learn;
}
//继承父类的原型,遍历原型对象,每一次的p都是原型的属性或者方法
for (var p in Person.prototype) {
Student.prototype[p] = Person.prototype[p];
}
Student.prototype.getLearn = function() {
console.log(this.learn);
}
Student.prototype.constructor = Student;
var student = new Student("张三", 19, "it");
student.getAge();
student.getName();
student.getLearn();
2,使用Object对象create,setPrototypeOf方法实现继承
关于assign的细节在这里。地址。使用assign可能会出现属性重复或者属性不可复制而产生异常。assign采用浅克隆,只复制最表面那一层的引用,引用的引用会被复制过去的修改,类似于python的函数传参浅拷贝。
var Person = function(name) {
this.name = name;
}
Person.prototype.say = function() { console.log('hello'); }
var Boy = function(sex) {
this.sex = sex;
}
Boy.prototype.hobby = 'football';
//继承基础属性
var Xiaomng = function(name, sex, age) {
this.age = age;
Person.call(this, name);
Boy.call(this, sex);
}
//继承Person的原型
Xiaomng.prototype = Object.create(Person.prototype); //create只能用一次
//继承Boy的原型,assign的作用是合并两个对象,将Boy.prototype的属性加到Xiaomng.prototype对象上
Object.assign(Xiaomng.prototype, Boy.prototype);
//添加Xiaoming构造函数的原型的constructor属性
Xiaomng.prototype.constructor = Xiaomng;
十三,严格模式
在js文件开头或者某一个函数方法之前添加"use strict"即可。严格模式将一些不合理的语法进行屏蔽。