JS面向对象二:this/原型链/new原理

JS面向对象二:this/原型链/new原理

阮一峰JavaScript教程:面向对象编程

阮一峰JavaScript教程:实例对象与 new 命令

阮一峰JavaScript教程:this 关键字

也可以看看这篇文章周大侠啊 进击的 JavaScript(六) 之 this先了解一下`this的四种绑定规则和箭头函数的this绑定

this

这两篇文章写的很好 周大侠啊 进击的 JavaScript(六) 之 this

苏云的博客

下面的this分别是什么?这几个函数都是回调函数,回调函数this比较特殊,通常是事件原对象

//1.
button1.onclick = function () {
    console.log(this)
}
//2.
button2.addEventListener("click", function () {
    console.log(this)
})
//3.jQuery中
$("ul").on("click", "li", function () {
    console.log(this)
})

this是函数.call()的第一个参数.

那么在直接调用函数的时候(隐式绑定,没用call),如何知道call()的第一个参数? 源码看不到,那就看文档.

看文档!: onclick:

addEventListener:

jQuery中:

所以上面三个的this分别是 btutton1元素,button2元素,li元素

$("ul").on("click", "li"/*selector*/, function () {
console.log(this)//代表与selector相匹配的元素(li元素)
})

thiscall()的第一个参数,只有写onclick,写addEventListener和写jQueryon的人想call()哪个东西,就把这个this绑定到哪里去了,所以要确定this,就要看源码或者文档!

例如:

button1.onclick = function () {
    console.log(this)
}
button1.onclick.call({name:"mataotao"})

可以直接触发onclick事件,传入{name:"mataotao"},那么this就是{name:"mataotao"}这个对象

以下来自苏云的博客()

6.回调函数的this 回调函数也只不过是函数的一种,实际上这种情况已经包含在了前面提到的情况中。但是由于回调函数的调用者往往不是我们自己,而是回调函数的接收者,即某个库或框架、甚至是JS运行时环境。这样一来,回调函数在中的this是什么就与对方的调用方式有关了,因此变得比较复杂,所以单独拿出来讨论一下。 情况1:没有明确作用对象的情况下,通常this为全局对象 例如setTimeout函数的回调函数,它的this就是全局对象。你如果希望自己指定this,可以通过bind函数等方法。 情况2:某个事件的监听器回调函数,通常this就是事件源对象 例如: button.addEventListener('click', fn) fn的中的this就是事件源button对象。 情况3:某些API会专门提供一个参数,用来指定回调函数中的this 例如,我们可以重新设计一个可以指定thissetTimeout: function setTimeoutExt(cb, period, thisArg) { setTimeout(function() { cb.call(thisArg); }, period); } 另外,在ExtJS中也大量使用了可以指定this的接口。

this题目

答案: 调用B处的console.log().结果是options window(console.log()中console是全局window对象里的一个方法)

第二题:

答案:D Object

第三题:

答案:Object

原型链

我终于明白了原型链: 仔细看下面这篇文章,就能明白原型链的构造问题: JavaScript 世界万物诞生记

个人理解: 原型链要分为两个部分,原型和链,原型就是一个实例对象,但是是最基础的实例对象.这个实例对象可以作为模板/类,让其他对象去复制他,复制之后不单单有这个原型的属性,也可以有自己的属性.新实现的实例对象.__proto__指向原来的模板实例对象. 而造出来的对象也可以当做模板,再由新的机器去以他为模板造新对象.由此形成了一条__proto__组成的链. 所有的对象都有__proto__属性,他们就像被链子连接在了一起,所以就称之为原型链

而复制的过程由一个机器来完成.这个机器(比如可以说是Object())的使用方法就是:按照模板实例对象new()一个新对象,新对象被原来的模板对象用__proto__链子拴着,新对象可以有自己的新添加的东西. 这个按照模板造新对象的机器.prototype指向原来的模板实例对象.prototype就是原来的模板实例对象拴住复制自己机器的链子.

写成代码就是:

var obj = new Object({ flag: 10 });

就像前面所说,机器用来制造某一类对象。正因如此,机器可以作为这类对象的标志,即面向对象语言中(class)的概念。所以机器又被称为构造函数。在ES6引入class关键字之前,我们常常把构造函数叫做类。说明2:用户自定义的函数通常既可以作为普通函数使用,又可以作为构造函数来制造对象。ES6新增的class语法定义的函数只能作为构造函数,ES6新增的=>语法定义的箭头函数只能作为普通函数

.

__proto__prototype的区别

__proto__是所有对象(包括函数对象)都有的一个属性(当然只是逻辑上有这么个概念),当我们说“原型链”的时候,就是指对象通过这个属性互相连接而形成的链状结构原型链也就是继承链prototype是只有函数(准确地说是构造函数)才有的一个属性,例如对于对于某个函数Fun。它的意义在于,当你用var obj = new Fun() 得到一个对象obj时,这个obj的原型就是F.prototype。即(new Fun()).__proto__ ===Fun.prototype,见文中第4个图。No. 1其实就是Object.prototype,No. 2其实就是Function.prototype。我只是为了强调这两个对象的重要性,故意这样说的。不太严格地说,前者就是一个空对象类似:{} ,后者就是一个空函数,类似:fubction() {} 。

文中: **No. 1:Object.prototype No. 2:Function.prototype**

还有这几篇文章也不错: 「每日一题」什么是 JS 原型链? - 方应杭的文章 - 知

周大侠啊 进击的 JavaScript 之 (七) 原型链

周大侠啊 进击的 JavaScript (八) 之 继承

new()

看看这篇文章很清楚: JS 的 new 到底是干什么的? - 方应杭的文章 - 知乎

new解决了什么

以共有属性对象为模板new出来的新对象的__proto__指向共有属性对象(我把这个对象叫做模板对象,也叫作原型).这样共有属性在内存中只需要存一次!

比如:当我们造士兵的时候,士兵有共有属性,有自有属性,那么我们可以把共有属性放在一个地方,避免每一次创建士兵都把共有属性重新创建一次,浪费内存:

既然这样,那么我们可以把制造士兵的过程写成一个函数.

然后调用即可

直接使用函数就可以制造一个有特殊的id,但是__proto__指向原型士兵的新士兵

那么可不可以直接把这个原型对象放到函数里,组成一个整体?不行,这样每次调用这个函数,都会在内存中创建这个临时对象,那么和原先的不用原型一样了

解决方法是,把这个原型变为函数的一个属性

这种方法省内存且好用.

new()就是刚刚的所有过程

灰色的代码就是new()做的封装,不需要你做的事情 共有属性被new()统一叫做prototype

new其实就是语法糖!

注意:.prototype对象最开始就是一个拥有constructor属性的对象,如果想修改共有属性,两种方法:

当我们new的时候我们做了什么:

new()的核心就是:

new应用举例:

第一步写私有属性,第二步写共有属性.

可以看到这个对象的 1自有属性, 2__proto__指向的原型对象含有共有属性. 3constructor指向的构造函数

节选文章

也可以看看这篇文章周大侠啊 进击的 JavaScript(六) 之 this 里面有new的实现.new与this 下面是节选:

五、new 绑定 如果 使用 new 来创建对象,因为 后面跟着的是构造函数,所以称它为构造器调用。对于this绑定来说,称为new绑定。 想知道 构造器调用 中 this 的绑定,就要知道 new 到底做了啥了。 先来个 new 的实现。看不懂不要紧,在后面原型链那篇,还会说的。 function New(proto){ //proto 为传进来的构造函数 var obj = {}; obj.__proto__ = proto.prototype; proto.apply(obj, Array.prototype.slice.call(argument,1)); //你这要看懂这步就行。这里把构造函数里的 this 绑定到了 新的obj 对象上,最后 返回了该新对象,作为实例对象。 return obj; } 所以在使用 new 来创建实例对象时,new 内部把 构造函数的 this 绑定到 返回的新对象 上了。 function Person(name){ this.name = name; } var c = new Person("zdx"); c.name;

JavaScript 世界万物诞生记中也提到了new的使用,new的过程就是生产机器按照模板原型对象造出来的新对象的过程!

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏互联网杂技

理解javascript闭包前,先理解作用域链

1. 全局作用域(Global Scope)   在代码中任何地方都能访问到的对象拥有全局作用域,一般来说以下几种情形拥有全局作用域:   (1)最外层函数和...

37550
来自专栏GreenLeaves

JS框架设计之对象类型判断一种子模块

Javascript有两套数据类型,一套是基础数据类型,一套是对象数据类型。基础数据类型包括5种基本数据类型,分别是null,bool,undefined,nu...

21680
来自专栏数据结构与算法

计算(calc.cpp)

计算(calc.cpp) 【问题描述】 小明在你的帮助下,破密了Ferrari设的密码门,正要往前走,突然又出现了一个密码门,门上有一个算式,其中只有“(”,“...

434100
来自专栏Golang语言社区

Go语言基本语法

前面已经看到了Go程序的基本结构,所以这将是很容易理解Go编程语言等基本构建块。 Go令牌 Go程序包括各种令牌和令牌可以是一个关键字,一个标识符,常量,字符串...

29460
来自专栏老司机的技术博客

人人都能学会的python编程教程4:关系运算符与循环

在python当中,if condition1:(注意最后的冒号:)称为“语句头”。冒号:之后另起一行缩进的是“语句体”,语句体的行数不限,但至少有一行,否则需...

35190
来自专栏iOSer成长记录

iOS-Strong/Copy修饰词

11930
来自专栏C/C++基础

C/C++文字常量与常变量

在C/C++编程时,经常遇到以下几个概念:常量、文字常量、字面常量、符号常量、字符常量、常变量、字符串常量等,网上的资料描述的不尽相同,弄得大家云里雾里。本文将...

15920
来自专栏SeanCheney的专栏

Python基础回顾基本数据类型和运算容器分支和循环函数、生成器和类map, reduce和filter列表生成(list comprehension)字符串文件操作和pickle异常多进程(mult

Python shell输入import this 可以看到The Zen of Python 基本数据类型和运算 基本数据类型 Python中最基本的数据类...

49570
来自专栏小詹同学

Python系列之——字符串格式化(xiaozhan is a boy of 22 years old.)

不知道小伙伴有没有遇到过字符串输出有格式要求的情况呢?今天小詹学习分享一波python的字符串格式化的方法。学以致用,首先我们得明确为什么要格式化字符串输出,以...

7620
来自专栏编程

宝宝都能学会的python编程教程4:关系运算符与循环

关系运算符 if 语句 实际应用中的程序,大多不是一撮而就的,而是根据条件不同存在很多分支。 最基本的条件分支结构是if...else...语句即如果。。。否则...

22890

扫码关注云+社区

领取腾讯云代金券