JS原型链与继承理解(新手向)(一)

前言

工作许久却很少写博客,一方面是工作太忙,平时不是在造轮子就是在改bug,加上文学不好,更加无心写博文。但是人的大脑是有限的,前端的领域涉及太多,知识点太多,难以记住全部,故整理记录下来,以供翻查。

JS数据类型

web前端主要就是围绕html+css+js来做,html+css的基础不说,js的基础更是能让你的开发之旅提升效率,码代码更加欢乐(滑稽)。学习js,最好的路线就是学习js中的类型和原型。

JS是一门弱语言,不像JAVA,C#等,类型之间不可强行转换。而在JS中,一个变量可以是任何类型,随意变换,故有流传的一句话:万物皆为对象

我们可以来验证一下,作为一个新手前端,先下载个chorme(谷歌浏览器)和代码编辑器(如:VsCodeSublime Text3),强烈推荐VsCode,作为一款免费的IDE,拥有大量的插件,涵盖了大量的语言编辑,前端方面还有各种各样流行库的代码提示,压缩,美化,终端等功能。

打开编辑器后,新建一个为Main.js的文件,然后编辑

var a = 1;// 定义一个变量为整型1
var b = '2';// 定义一个变量为字符串2
var c = false;// 定义一个变量为布尔型
var d = new Object();// 定义一个变量为Object类型
var e = undefined;// 定义一个变量为undefined
var f = null;// 定义一个变量为null
var g = Symbol();// 定义一个变量为Symbol类型,这个类型是ES6加入的,详细后面再讲。

// 我们使用typeof 关键字 这个来检测变量的类型

console.log(typeof a);// number
console.log(typeof b);// string
console.log(typeof c);// boolean
console.log(typeof d);// object
console.log(typeof e);// undefined
console.log(typeof f);// object
console.log(typeof g);// symbol

这时候有人要问了,你这打印出来的不全是object啊,跟你说的不一样啊。

稍安勿躁,让我给你慢慢解释。自从盘古开天辟地,混沌化作宇宙洪荒…(咳咳咳)扯远了。要想知道为什么JS中万物皆为对象,得先从数据类型讲起。
JS中拥有两种数据类型,一种是基本数据类型,一种是引用数据类型(也称之为对象类型)。

基本数据类型有 NumberStringBooleanUndefinedNullSymbol
引用数据类型有 Object

所以也有说JS有7种数据类型(ES6加入了一种),那么基本数据类型和引用数据类型有啥区别呢?让我们用代码来展示一下吧。

var a = 1;
a.name = 'xiaoming';
console.log(a.name);// undefined

var b = {};
b.name = 'xiaohong';
console.log(b.name);// xiaohong

// 从这里我们可以看出,正常下基本数据类型是不能往里添加属性和方法的,引用类型是可以的。我们继续。

var c = a;
c = 2;
console.log(a);// 1

var d = b;
d.name = 'xiaolan';
console.log(b.name);// xiaolan

// 可能有人会不明白,为什么a还是1,但是d的name却变成了小兰呢?我们来看一张图。

JS类型在内存内描述
JS中的基础数据类型,这些值都有固定的大小,往往都保存在栈内存中(闭包除外),由系统自动分配存储空间。我们复制该变量的时候,会从内存中开辟一个新的,然后复制该值保存,所以
b的修改不会涉及到a。

JS的引用数据类型,比如数组Array,它们值的大小是不固定的。引用数据类型的值是保存在堆内存中的对象。在操作对象时,实际上是在操作对象的引用而不是实际的对象。当我们复制该变量时,就会将新的变量指向该对象,所以d和c是同一个对象,修改d时,c读取的也是修改之后的。

我们理解完数据类型,让我们来看一下这一节的重点:构造函数和prototype(原型)

构造函数和prototype(原型)

何为构造函数,构造函数是对象生成时调用的函数。

包括基础数据类型定义时,虽然定义之后没办法动态添加属性和方法,但是定义时会调用封装的构造函数添加属性和方法。如’1’.length, 1.toString

让我们来写个构造函数

function Person() {
	this.age = 11;
	this.say = function() {
		console.log('hello');
	};
}

var user = new Person();
console.log(user.age);// 11
user.say = function() {
	console.log('hi');
};
user.say();// hi

var user2 = new Person();
console.log(user2.age);// 11
user2.say();// hello

这里定义了一个构造函数PersonPerson拥有一个属性age和一个函数say。但是当我们定义两个user对象的时候,修改了第一个的say方法,第二个的say还是原来的方法。在两个对象中可能看不出什么,但是如果要定义很多的user对象,我们不可能更改所有的user对象的say方法。这时候prototype就要站出来了。

prototype(原型)和[[prototype]]

prototype又称原型,每个函数都会默认存在一个属性prototypeprototype也是一个对象,默认拥有constructor属性,该属性默认指向本身的构造函数prototype的属性和函数可以被所有该函数生成的对象调用,是共享的。

PS:null,undefined不存在[[prototype]]。

每个对象在生成的时候会默认生成一个 [[prototype]] ,一般称 [[prototype]] 为隐式原型,指向该对象的构造函数prototype,在大多数浏览器内 [[prototype]] 为__proto__(之后都会使用__proto__来表示对象的 [[prototype]] )。

我们通常在ES5中用Object.getPrototypeOf函数获得一个对象的 [[prototype]] 。ES6中,使用Object.setPrototypeOf可以直接修改一个对象的 [[prototype]] 。

突然一大堆名词和逻辑是不是有点绕,那就让我们开始码段代码(滑稽)。

// 承接上面的代码,我们将Person函数修改一下

function Person (name) {
	this.name = name;
	Person.prototype.age = 11;
	Person.prototype.say = function() {
		console.log("I'm " + this.name);
	};
}

var user = new Person();
console.log(user.__proto__);

代码示意
从打印的结果可以看到,user.__proto__是拥有age和say的,而且__proto__的constructor指向Person函数。

var user2 = new Person('xiaoming');
user2.say();// I'm xiaoming
console.log(user2.age);// 11

var user3 = new Person('xiaohong');
user3.say();// I'm xiaohong
Person.prototype.age = 18;
console.log(user3.age);// 18

我们修改了Person.prototype.age的同时,所有使用Person实例的对象的age也修改了。我们可以使用prototype来声明我们的公用属性和函数。

第一小节就到此结束了,剩下的内容放到下一小节。

新手博主,文才不佳,如有发现错误,请提醒我修改,轻喷,多谢大家!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值