JavaScript-this指向继承(构造函数和原型对象)

Posted 速速逃离月球表面

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript-this指向继承(构造函数和原型对象)相关的知识,希望对你有一定的参考价值。

1. this关键字

  • 构造函数中的this指的是新创建的对象,不代表这个类,指的是由类指针创建出来的对象
  • 直接通过函数名调用函数(普通函数),this指的是全局对象window(构造函数只能通过new运算符调用,不能直接显示调用)
  • 如果将函数作为对象的方法调用,this会指向该对象
  • 普通函数中加不加this都可以,默认this指向window

1.1 案例:分析this指向

function foo() {
	return this
}
var o = {
	name: 'Jim',
	func: foo
}
console.log(foo() === window) //对应第二种情况,输出结果:true
console.log(o.func() === o)   //对应第三种情况,输出结果:true

1.2 更改this的指向

javascript 为专门提供了一些函数方法来处理函数内部 this 的指向问题,常用的有 bind()call()apply() 三种方法。
在这里插入图片描述
apply()方法和call()方法的区别

function method(a, b) {
	console.log(a + b)
}
method.apply({}, ['1', '2'])  //数组方式传参,输出结果:12
method.call({}, '3', '4')     //参数方式传参,输出结果:34

bind()方法

function method(a, b) {
	console.log(this.name + a + b)
}
var name = '张三'
var test = method.bind({ name: '李四' }, '3', '4')  //-->表示method方法绑定了{name:'李四'}对象,method中的this指向的就是{name:'李四'}的对象
method('1', '2')  //输出结果:张三12    -->该方法中的this指的是window
test()            //输出结果:李四34

2. 错误处理

try-catch语法

try{
	可能会出现错误的代码
}catch(e ) {        //e--->出现错误的代码的错误类型
	错误出现后的处理代码
}

throw抛出错误对象案例演示

try {
	var e1 = new Error('错误信息')  //创建错误对象
	throw e1  //抛出错误对象,也可以与上一行合并为:throw new Error('错误信息')
} catch (e) {
	console.log(e.message)  //输出结果:错误信息
	console.log(e1 === e)  //判断e1和e是否为同一个对象,输出结果为:true
}

错误类型

类型说明
Error普通错误,其余6种类型的错误对象都继承自该对象
EvalError调用eval()函数错误,已经弃用,为了向后兼容,低版本还可以使用
RangeError数值超出有效范围,如“new Array(-1)"
ReferenceError引用了一个不存在的变量,如“var a = 1; a + b"(变量B未定义)
SyntaxError解析过程语法错误,如" { ; } " “if()” “var a = new”
TypeError变量或参数不是预期类型,如调用了不存在的函数或方法
URIError解析URI编码出错,调用encodeURI()、escape()等URI处理函数时出现

3. 继承

ES6之前并没有提供 extends 继承。可以通过构造函数+原型对象模拟实现继承,被称为组合继承

call()
作用:调用这个函数,并且修改函数运行时this指向将父类的this指向子类的this,实现子类继承父类的属性
实例对象:使用new运算符,调用构造函数创建的对象

3.1 借用构造函数继承父亲属性

原理: 通过call()方法 将父类的this指向子类的this,实现子类继承父类的属性
实例对象:使用new运算符,调用构造函数创建的对象

function Father(uname, age) { //Father构造函数是父类
	//this指向父构造函数的对象实例
	this.uname = uname
	this.age = age
}
function Son(uname, age, score) { //Son构造函数是子类
	//this指向子构造函数的对象实例
	//将父构造函数的属性拿过来调用(实现父构造函数的借用),即实现对父构造函数的继承
	Father.call(this, uname, age) //子类继承父类的属性
	this.score = score            //子类可以拥有自己的特有属性
}
var son = new Son('张三', 18, 100)
console.log(son)   //输出结果:Son{uname:'张三',age:18,score:100}

ES6中继承父亲属性

// 使用super继承(ES6)
class Father {
    constructor(name, age) {
        this.name = name
        this.age = age
    }
}
class Son extends Father {
    constructor(name, age, score) {
        super(name, age)
        this.score = score
    }
}
var son = new Son('张三', 20, 90)
console.log(son)  //输出结果:Son {name: "张三", age: 20, score: 90}

3.2 利用原型对象继承父类方法

一般情况下,对象的方法都在构造函数的原型对象中设置,通过构造函数无法继承父类方法。

原型对象继承父类方法:将父类的实例对象作为子类的原型对象来使用

核心原理

  • 将子类所共享的方法提取出来,让子类的 prototype 原型对象 = new 父类()
  • 本质:子类原型对象等于是实例化父类,因为父类实例化之后另外开辟空间,就不会影响原来父类原型对象
  • 将子类的 constructor 从新指向子类的构造函数
function Father() { }
Father.prototype.money = function () {
	console.log(100000)
}
function Son() { }
//Son.prototype = Father.prototype   //这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
Son.prototype = new Father()  //将父类的实例对象作为子类的原型对象
//这个是子构造函数专门的方法
//如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的原型对象
Son.prototype.constructor = Son  //将原型对象的contructor属性指向子类
new Son().money()  //调用父类的money()方法,输出结果:100000
Son.prototype.exam = function () { }  //为子类增加exam()方法
console.log(Father.prototype.exam)  //子类不影响父类,输出结果:undefined

原型链示意图
在这里插入图片描述
class语法的本质:类和构造函数的使用非常相似,可以互相替代

<script>
    class Person { }
    console.log(Person.prototype)  //类也有原型对象
    Person.prototype.money = function () {  //类也可以增加方法
        console.log(100000)
    }
    new Person().money()  //输出结果:100000
</script>

4. 类的本质

ES6之前通过 构造函数+原型 实现面向对象编程
ES6通过 类 实现面向对象编程

  • class本质还是function,也可以简单认为类就是构造函数的另一种写法
    构造函数的特征:
  1. 构造函数有原型对象prototype
  2. 构造函数原型对象prototype里面有constructor指向构造函数本身
  3. 构造函数可以通过原型对象添加方法
  4. 构造函数创建的实例对象由__proto__原型指向构造函数的原型对象
  • 类的所有方法都定义在类的prototype属性上
  • 创建的实例,里面也proto 指向类的prototype 原型对象
  • 类可以通过原型对象来添加方法
  • 所以ES6的类它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。
  • 所以ES6的类其实就是语法糖.
  • 语法糖:语法糖就是一种便捷写法. 简单理解, 有两种方法可以实现同样的功能, 但是一种写法更加清晰、方便,那么这个方法就是语法糖

补充:

URI和URL的区别:

  • URI,是uniform resource identifier,统一资源标识符,用来唯一的标识一个资源。
  • URL是uniform resource locator,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源,而且还指明了如何locate这个资源。
  • 也就是说,URI是以一种抽象的,高层次概念定义统一资源标识,而URL和URN则是具体的资源标识的方式。URL和URN都是一种URI。

http和https的区别:

https的SSL加密是在传输层实现的。
(1)http和https的基本概念

http: 超文本传输协议,是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器端请求和应答的标准(TCP),用于从WWW服务器传输超文本到本地浏览器的传输协议,它可以使浏览器更加高效,使网络传输减少。

https: 是以安全为目标的HTTP通道,简单讲是HTTP的安全版,即HTTP下加入SSL层,HTTPS的安全基础是SSL,因此加密的详细内容就需要SSL。

https协议的主要作用是:建立一个信息安全通道,来确保数组的传输,确保网站的真实性。

(2)http和https的区别?

http传输的数据都是未加密的,也就是明文的,网景公司设置了SSL协议来对http协议传输的数据进行加密处理,简单来说https协议是由http和ssl协议构建的可进行加密传输和身份认证的网络协议,比http协议的安全性更高。
主要的区别如下:

Https协议需要ca证书,费用较高。

http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。

使用不同的链接方式,端口也不同,一般而言,http协议的端口为80,https的端口为443

http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

(3)https协议的工作原理

客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤,如图所示。

客户使用https url访问服务器,则要求web 服务器建立ssl链接。

web服务器接收到客户端的请求之后,会将网站的证书(证书中包含了公钥),返回或者说传输给客户端。

客户端和web服务器端开始协商SSL链接的安全等级,也就是加密等级。

客户端浏览器通过双方协商一致的安全等级,建立会话密钥,然后通过网站的公钥来加密会话密钥,并传送给网站。

web服务器通过自己的私钥解密出会话密钥。

web服务器通过会话密钥加密与客户端之间的通信。

(4)https协议的优点

使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;

HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。

HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。

谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。

(5)https协议的缺点

https握手阶段比较费时,会使页面加载时间延长50%,增加10%~20%的耗电。

https缓存不如http高效,会增加数据开销。

SSL证书也需要钱,功能越强大的证书费用越高。

SSL证书需要绑定IP,不能再同一个ip上绑定多个域名,ipv4资源支持不了这种消耗。

以上是关于JavaScript-this指向继承(构造函数和原型对象)的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript this指向ES5组合继承(构造函数+原型对象)错误处理

继承(构造函数+原型对象模拟实现继承)

JS高级---借用构造函数

构造函数和实例的关系

JavaScript继承的6种方式

继承 (js原型链)