js面向对象,js原型,原型链,prototype,_proto_

目录

一,理解类、对象、面向对象编程

二,声明一个类——构造函数

三,prototype原型

1,为什么需要原型prototype?

2,在一个构造函数的原型中添加属性和方法

四,给构造函数添加静态属性和静态方法

五,给实例对象instance添加实例属性和实例方法

六,构造函数的原型与实例对象自身属性与方法同名

七,实例对象的__proto__属性

1,__proto__属性指向谁?

2,构造函数原型prototype的__proto__指向Object.prototype

3,Object对象的原型对象的__proto__属性指向null

4,普通函数的__proto__指向Function.prototype

八,原型对象的constructor属性指向该原型的构造函数

九,由__proto__属性构成的原型链

1,什么是原型链?

2,一张图看懂原型链

十,instanceof运算符

十一,Object对象的相关方法

1,Object.getPrototypeOf()获取对象原型

2,Object.setPrototypeOf()将一个对象设为另一个对象的原型

3,Object.create()方法实现实时动态继承 

3.1 单参数实现复用别的代码

3.2 双参数实现既复用又新添加

4,Object.getOwnPropertyNames()返回一个对象所有的属性数组

5,Object.hasOwnPropertyNames()判断一属性是否属于对象自身

十二,js对象的继承

1,继承的一般写法

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,一张图看懂原型链

fd99ecdcd9c545d184e9c950c40d24a3.png

十,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"即可。严格模式将一些不合理的语法进行屏蔽。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值