this是什么?作什么?指向是什么?javascript
函数中this调用:this-----》windowcss
方法中this调用:this-----》当前对象(嗲用方法的对象)html
构造函数中this调用:this------》该构造函数的实例对象java
借用方法调用:改变this的指向node
分析this的问题,须要明白两点:(只看函数是怎么被调用的,无论函数是怎么来的)css3
1.分析this是属于哪一个函数程序员
2.分析该函数是以什么模式被调用的es6
要说 JavaScript 这门语言最容易让人困惑的知识点,this
关键词确定算一个。JavaScript 语言面世多年,一直在进化完善,如今在服务器上还能够经过 node.js 来跑 JavaScript。显然,这门语言还会活好久。web
因此说,我一直相信,若是你是一个 JavaScript 开发者或者说 web 开发者,学好 JavaScript 的运做原理以及语言特色确定对你之后大有好处。编程
在开始正文以前,我强烈推荐你先掌握好下面的知识:
若是没有对这些基础知识掌握踏实,直接讨论 JavaScript 的 this
关键词只会让你感到更加地困惑和挫败。
this
?若是上面的简单介绍没有说服你来深刻探索 this
关键词,那我用这节来说讲为何要学。
考虑这样一个重要问题,假设开发者,好比 Douglas Crockford (译者注:JavaScript 领域必知牛人),再也不使用 new
和 this
,转而使用完彻底全的函数式写法来作代码复用,会怎样?
事实上,基于 JavaScript 内置的现成的原型继承功能,咱们已经使用而且将继续普遍使用 new
和 this
关键词来实现代码复用。
理由一,若是只能使用本身写过的代码,你是无法工做的。现有的代码以及你读到这句话时别人正在写的代码都颇有可能包含 this
关键词。那么学习怎么用好它是否是颇有用呢?
所以,即便你不打算在你的代码库中使用它,深刻掌握 this
的原理也能让你在接手别人的代码理解其逻辑时事半功倍。
理由二,拓展你的编码视野和技能。使用不一样的设计模式会加深你对代码的理解,怎么去看、怎么去读、怎么去写、怎么去理解。咱们写代码不只是给机器去解析,仍是写给咱们本身看的。这不只适用于 JavaScript,对其余编程语言亦是如此。
随着对编程理念的逐步深刻理解,它会逐渐塑造你的编码风格,无论你用的是什么语言什么框架。
就像毕加索会为了得到灵感而涉足那些他并非很赞同很感兴趣的领域,学习 this 会拓展你的知识,加深对代码的理解。
this
?在我开始讲解前,若是你学过一门基于类的面向对象编程语言(好比 C#,Java,C++),那请将你对 this
这个关键词应该是作什么用的先入为主的概念扔到垃圾桶里。JavaScript 的 this
关键词是很不同,由于 JavaScript 原本就不是一门基于类的面向对象编程语言。
虽然说 ES6 里面 JavaScript 提供了类这个特性给咱们用,但它只是一个语法糖,一个基于原型继承的语法糖。
this
就是一个指针,指向咱们调用函数的对象。
我难以强调上一句话有多重要。请记住,在 Class 添加到 ES6 以前,JavaScript 中没有 Class 这种东西。Class 只不过是一个将对象串在一块儿表现得像类继承同样的语法糖,以一种咱们已经习惯的写法。全部的魔法背后都是用原型链编织起来的。
若是上面的话很差理解,那你能够这样想,this 的上下文跟英语句子的表达很类似。好比下面的例子
Bob.callPerson(John);
就能够用英语写成 “Bob called a person named John”。因为 callPerson()
是 Bob 发起的,那 this
就指向 Bob。咱们将在下面的章节深刻更多的细节。到了这篇文章结束时,你会对 this
关键词有更好的理解(和信心)。
执行上下文 是语言规范中的一个概念,用通俗的话讲,大体等同于函数的执行“环境”。具体的有:变量做用域(和 做用域链条,闭包里面来自外部做用域的变量),函数参数,以及
this
对象的值。引自: Stackoverflow.com
记住,如今起,咱们专一于查明 this
关键词到底指向哪。所以,咱们如今要思考的就一个问题:
为了理解这个关键概念,咱们来测一下下面的代码。
var person = { name: "Jay", greet: function() { console.log("hello, " + this.name); } }; person.greet();
谁调用了 greet 函数?是 person
这个对象对吧?在 greet()
调用的左边是一个 person 对象,那么 this 关键词就指向 person
,this.name
就等于 "Jay"
。如今,仍是用上面的例子,我加点料:
var greet = person.greet; // 将函数引用存起来; greet(); // 调用函数
你以为在这种状况下控制台会输出什么?“Jay”?undefined
?仍是别的?
正确答案是 undefined
。若是你对这个结果感到惊讶,没必要惭愧。你即将学习的东西将帮助你在 JavaScript 旅程中打开关键的大门。
this
的值并非由函数定义放在哪一个对象里面决定,而是函数执行时由谁来唤起决定。
对于这个意外的结果咱们暂且压下,继续看下去。(感受先后衔接得不够流畅)
带着这个困惑,咱们接着测试下 this
三种不一样的定义方式。
this
的指向上一节咱们已经对 this
作了测试。可是这块知识实在重要,咱们须要再好好琢磨一下。在此以前,我想用下面的代码给你出个题:
var name = "Jay Global"; var person = { name: 'Jay Person', details: { name: 'Jay Details', print: function() { return this.name; } }, print: function() { return this.name; } }; console.log(person.details.print()); // ? console.log(person.print()); // ? var name1 = person.print; var name2 = person.details; console.log(name1()); // ? console.log(name2.print()) // ?
console.log()
将会输出什么,把你的答案写下来。若是你还想不清楚,复习下上一节。
准备好了吗?放松心情,咱们来看下面的答案。
首先,谁调用了 print 函数?在 JavaScript 中咱们都是从左读到右。因而 this 指向 details
而不是 person
。这是一个很重要的区别,若是你对这个感到陌生,那赶忙把它记下。
print
做为 details
对象的一个 key,指向一个返回 this.name
的函数。既然咱们已经找出 this 指向 details ,那函数的输出就应该是 'Jay Details'
。
再来一次,找出 this
的指向。print()
是被 person
对象调用的,没错吧?
在这种状况,person
里的 print
函数返回 this.name
。this
如今指向 person
了,那 'Jay Person'
就是返回值。
这一题就有点狡猾了。在上一行有这样一句代码:
var name1 = person.print;
若是你是经过这句来思考的,我不会怪你。很遗憾,这样去想是错的。要记住,this
关键词是在函数调用时才作绑定的。name1()
前面是什么?什么都没有。所以 this
关键词就将指向全局的 window
对象去。
所以,答案是 'Jay Global'
。
看一下 name2
指向哪一个对象,是 details
对象没错吧?
因此下面这句会打印出什么呢?若是到目前为止的全部小点你都理解了,那这里稍微思考下你就天然有答案了。
console.log(name2.print()) // ??
答案是 'Jay Details'
,由于 print
是 name2
调起的,而 name2
指向 details
。
你可能会问:“什么是词法做用域?”
逗我呢,咱们不是在探讨 this
关键词吗,这个又是哪里冒出来的?好吧,当咱们用起 ES6 的箭头函数,这个就要考虑了。若是你已经写了不止一年的 JavaScript,那你极可能已经碰到箭头函数。随着 ES6 逐渐成为现实标准,箭头函数也变得愈来愈经常使用。
JavaScript 的词法做用域 并很差懂。若是你 理解闭包,那要理解这个概念就容易多了。来看下下面的小段代码。
// outerFn 的词法做用域 var outerFn = function() { var n = 5; console.log(innerItem); // innerFn 的词法做用域 var innerFn = function() { var innerItem = "inner"; // 错了。只能坐着电梯向上,不能向下。 console.log(n); }; return innerFn; }; outerFn()();
想象一下一栋楼里面有一架只能向上走的诡异电梯。
建筑的顶层就是全局 windows 对象。若是你如今在一楼,你就能够看到并访问那些放在楼上的东西,好比放在二楼的 outerFn
和放在三楼的 window
对象。
这就是为何咱们执行代码 outerFn()()
,它在控制台打出了 5 而不是 undefined
。
然而,当咱们试着在 outerFn
词法做用域下打出日志 innerItem
,咱们遇到了下面的报错。请记住,JavaScript 的词法做用域就好像建筑里面那个只能向上走的诡异电梯。因为 outerFn 的词法做用域在 innerFn 上面,因此它不能向下走到 innerFn 的词法做用域里面并拿到里面的值。这就是触发下面报错的缘由:
test.html:304 Uncaught ReferenceError: innerItem is not defined at outerFn (test.html:304) at test.html:313
this
和箭头函数在 ES6 里面,无论你喜欢与否,箭头函数被引入了进来。对于那些还没用惯箭头函数或者新学 JavaScript 的人来讲,当箭头函数和 this
关键词混合使用时会发生什么,这个点可能会给你带来小小的困惑和淡淡的忧伤。那这个小节就是为大家准备的!
当涉及到
this
关键词,箭头函数 和 普通函数 主要的不一样是什么?
答案:
箭头函数按词法做用域来绑定它的上下文,因此
this
实际上会引用到原来的上下文。引自:hackernoon.com
我实在无法给出比这个更好的总结。
箭头函数保持它当前执行上下文的词法做用域不变,而普通函数则不会。换句话说,箭头函数从包含它的词法做用域中继承到了 this
的值。
咱们不妨来测试一些代码片断,确保你真的理解了。想清楚这块知识点将来会让你少点头痛,由于你会发现 this
关键词和箭头函数太常常一块儿用了。
仔细阅读下面的代码片断。
var object = { data: [1,2,3], dataDouble: [1,2,3], double: function() { console.log("this inside of outerFn double()"); console.log(this); return this.data.map(function(item) { console.log(this); // 这里的 this 是什么?? return item * 2; }); }, doubleArrow: function() { console.log("this inside of outerFn doubleArrow()"); console.log(this); return this.dataDouble.map(item => { console.log(this); // 这里的 this 是什么?? return item * 2; }); } }; object.double(); object.doubleArrow();
若是咱们看执行上下文,那这两个函数都是被 object
调用的。因此,就此判定这两个函数里面的 this 都指向 object
不为过吧?是的,但我建议你拷贝这段代码而后本身测一下。
这里有个大问题:
arrow()
和doubleArrow()
里面的map
函数里面的this
又指向哪里呢?
上一张图已经给了一个大大的提示。若是你还不肯定,那请花5分钟将咱们上一节讨论的内容再好好想一想。而后,根据你的理解,在实际执行代码前把你认为的 this 应该指向哪里写下来。在下一节咱们将会回答这个问题。
这个标题已经把答案泄露出来了。在你看不到的地方,map 函数对调用它的数组进行遍历,将数组的每一项传到回调函数里面并把执行结果返回。若是你对 JavaScript 的 map 函数不太了解或有所好奇,能够读读这个了解更多。
总之,因为 map()
是被 this.data
调起的,因而 this 将指向那个存储在 data
这个 key 里面的数组,即 [1,2,3]
。一样的逻辑,this.dataDouble
应该指向另外一个数组,值为 [1,2,3]
。
如今,若是函数是 object
调用的,咱们已经肯定 this 指向 object
对吧?好,那来看看下面的代码片断。
double: function() { return this.data.map(function(item) { console.log(this); // 这里的 this 是什么?? return item * 2; }); }
这里有个颇有迷惑性的问题:传给 map()
的那个匿名函数是谁调用的?答案是:这里没有一个对象是。为了看得更明白,这里给出一个 map
函数的基本实现。
// Array.map polyfill if (Array.prototype.map === undefined) { Array.prototype.map = function(fn) { var rv = []; for(var i=0, l=this.length; i<l; i++) rv.push(fn(this[i])); return rv; }; }
fn(this[i]));
前面有什么对象吗?没。所以,this
关键词指向全局的 windows 对象。那,为何 this.dataDouble.map
使用了箭头函数会使得 this 指向 object
呢?
我想再说一遍这句话,由于它实在很重要:
箭头函数按词法做用域将它的上下文绑定到 原来的上下文
如今,你可能会问:原来的上下文是什么?问得好!
谁是 doubleArrow()
的初始调用者?就是 object
对吧?那它就是原来的上下文
use strict
为了让 JavaScript 更加健壮及尽可能减小人为出错,ES5 引进了严格模式。一个典型的例子就是 this 在严格模式下的表现。你若是想按照严格模式来写代码,你只须要在你正在写的代码的做用域最顶端加上这么一行 "use strict;"
。
记住,传统的 JavaScript 只有函数做用域,没有块做用域。举个例子:
function strict() { // 函数级严格模式写法 'use strict'; function nested() { return 'And so am I!'; } return "Hi! I'm a strict mode function! " + nested(); } function notStrict() { return "I'm not strict."; }
代码片断来自 Mozilla Developer Network。
不过呢,ES6 里面经过 let 关键词提供了块做用域的特性。
如今,来看一段简单代码,看下 this 在严格模式和非严格模式下会怎么表现。在继续以前,请将下面的代码运行一下。
(function() { "use strict"; console.log(this); })(); (function() { // 不使用严格模式 console.log(this); })();
正如你看到的,this
在严格模式下指向 undefined
。相对的,非严格模式下 this
指向全局变量 window
。大部分状况下,开发者使用 this ,并不但愿它指向全局 window 对象。严格模式帮咱们在使用 this
关键词时,尽可能少作搬起石头砸本身脚的蠢事。
举个例子,若是全局的 window 对象恰好有一个 key 的名字和你但愿访问到的对象的 key 相同,会怎样?上代码吧:
(function() { // "use strict"; var item = { document: "My document", getDoc: function() { return this.document; } } var getDoc = item.getDoc; console.log(getDoc()); })();
这段代码有两个问题。
this
将不会指向 item
。window
对象也有一个名为 document
的属性。在这个简单示例中,由于代码较短也就不会造成大问题。
若是你是在生产环境像上面那样写,当用到 getDoc
返回的数据时,你将收获一堆难以定位的报错。若是你代码库比较大,对象间互动比较多,那问题就更严重了。
值得庆幸的是,若是咱们是在严格模式下跑这段代码,因为 this 是 undefined
,因而马上就有一个报错抛给咱们:
test.html:312 Uncaught TypeError: Cannot read property 'document' of undefined
at getDoc (test.html:312)
at test.html:316
at test.html:317
先前假定你们都对执行上下文不熟,因而咱们聊了不少关于执行上下文和 this 的知识。
让人欢喜让人忧的是,在 JavaScript 中经过使用内置的特性开发者就能够直接操做执行上下文了。这些特性包括:
this
的值准确设置到你选择的一个对象上。还能够经过逗号隔开传递多个参数,如 func.bind(this, param1, param2, ...)
。this
的值准确设置到你选择的一个对象上。第二个参数是一个数组,数组的每一项是你但愿传递给函数的参数。最后,执行函数。this
的值准确设置到你选择的一个对象上,而后想 bind
同样经过逗号分隔传递多个参数给函数。如:print.call(this, param1, param2, ...)
。最后,执行函数。上面提到的全部内置函数都有一个共同点,就是它们都是用来将 this
关键词指向到其余地方。这些特性可让咱们玩一些骚操做。只是呢,这个话题太广了都够写好几篇文章了,因此简洁起见,这篇文章我不打算展开它的实际应用。
重点:上面那三个函数,只有 bind()
在设置好 this
关键词后不马上执行函数。
你可能在想:如今已经很乱了,学习全部这些的目的是什么?
首先,你会看到 bind、call 和 apply 这几个函数处处都会用到,特别是在一些大型的库和框架。若是你没理解它作了些什么,那可怜的你就只用上了 JavaScript 提供的强大能力的一小部分而已。
若是你不想了解一些可能的用法而想马上读下去,固然了,你能够直接跳过这节,不要紧。
下面列出来的应用场景都是一些具备深度和广度的话题(一篇文章基本上是讲不完的),因此我放了一些连接供你深度阅读用。将来我可能会在这篇终极指南里面继续添加新的小节,这样你们就能够一次看过瘾。
若是我漏掉了其余实践案例,请留言告知。我会常常来优化这篇指南,这样你做为读者就能够读到最丰富的内容。
阅读高质量的开源代码能够升级你的知识和技能。
讲真,你会在一些开源代码上看到 this 关键词、call、apply 和 bind 的实际应用。我会将这块结合着其余能帮你成为更好的程序员的方法一块儿讲。
在我看来,开始阅读最好的开源代码是 underscore。它并不像其余开源项目,如 d3,那样铁板一块,而是内部代码相互比较独立,于是它是教学用的最佳选择。另外,它代码简洁,文档详细,编码风格也是至关容易学习。
this
和 bind前面提到了,bind
容许你明确设定 this 的指向而不用实际去执行函数。这里是一个简单示例:
var bobObj = { name: "Bob" }; function print() { return this.name; } // 将 this 明确指向 "bobObj" var printNameBob = print.bind(bobObj); console.log(printNameBob()); // this 会指向 bob,因而输出结果是 "Bob"
在上面的示例中,若是你把 bind 那行去掉,那 this 将会指向全局 window
对象。
这好像很蠢,但在你想将 this
绑定到具体对象前你就必须用 bind
来绑定。在某些场景下,咱们可能想从另外一个对象中借用一些方法。举个例子,
var obj1 = { data: [1,2,3], printFirstData: function() { if (this.data.length) return this.data[0]; } }; var obj2 = { data: [4,5,6], printSecondData: function() { if (this.data.length > 1) return this.data[1]; } }; // 在 obj1 中借用 obj2 的方法 var getSecondData = obj2.printSecondData.bind(obj1); console.log(getSecondData()); // 输出 2
在这个代码片断里,obj2
有一个名为 printSecondData
的方法,而咱们想将这个方法借给 obj1
。在下一行
var getSecondData = obj2.printSecondData.bind(obj1);
经过使用 bind ,咱们让 obj1
能够访问 obj2
的 printSecondData
方法。
在下面的代码中
var object = { data: [1,2,3], double: function() { this.data.forEach(function() { // Get this to point to object. console.log(this); }); } }; object.double();
怎么让 this 关键词指向 object
。提示:你并不须要重写 this.data.forEach
。
在上一节中,咱们了解了执行上下文。若是你对匿名函数调用那部分看得够细心,你就知道它并不会做为某个对象的方法被调用。所以,this
关键词指向了全局 window
对象。
因而咱们须要将 object 做为上下文绑定到匿名函数上,使得里面的 this 指向 object
。如今,double
函数跑起来时,是 object
调用了它,那么 double
里面的 this
指向 object
。
var object = { data: [1,2,3], double: function() { return this.data.forEach(function() { // Get this to point to object. console.log(this); }.bind(this)); } }; object.double();
那,若是咱们像下面这样作呢?
var double = object.double; double(); // ??
double()
的调用上下文是什么?是全局上下文。因而,咱们就会看到下面的报错。
Uncaught TypeError: Cannot read property 'forEach' of undefined
at double (test.html:282)
at test.html:289
因此,当咱们用到 this
关键词时,就要当心在乎咱们调用函数的方式。咱们能够在提供 API 给用户时固定 this 关键词,以此减小这种类型的错误。但请记住,这么作的代价是牺牲了灵活性,因此作决定前要考虑清楚。
var double = object.double.bind(object); double(); // 再也不报错
this
和 callcall 方法和 bind 很类似,但就如它名字所暗示的,call
会马上呼起(执行)函数,这是两个函数的最大区别。
var item = { name: "I am" }; function print() { return this.name; } // 马上执行 var printNameBob = console.log(print.call(item));
call
、apply
、bind
大部分使用场景是重叠的。做为一个程序员最重要的仍是先了解清楚这三个方法之间的差别,从而能根据它们的设计和目的的不一样来选用。只要你了解清楚了,你就能够用一种更有创意的方式来使用它们,写出更独到精彩的代码。
在参数数量固定的场景,call
或 bind
是不错的选择。好比说,一个叫 doLogin
的函数常常是接受两个参数:username
和 password
。在这个场景下,若是你须要将 this 绑定到一个特定的对象上,call
或 bind
会挺好用的。
之前一个最经常使用的场景是把一个类数组对象,好比 arguments
对象,转化成数组。举个例子:
function convertArgs() { var convertedArgs = Array.prototype.slice.call(arguments); console.log(arguments); console.log(Array.isArray(arguments)); // false console.log(convertedArgs); console.log(Array.isArray(convertedArgs)); // true } convertArgs(1,2,3,4);
在上面的例子中,咱们使用 call 将 argument
对象转化成一个数组。在下一个例子中,咱们将会调用一个 Array
对象的方法,并将 argument 对象设置为方法的 this,以此来将传进来参数加在一块儿。
function add (a, b) { return a + b; } function sum() { return Array.prototype.reduce.call(arguments, add); } console.log(sum(1,2,3,4)); // 10
咱们在一个类数组对象上调用了 reduce 函数。要知道 arguments 不是一个数组,但咱们给了它调用 reduce 方法的能力。若是你对 reduce 感兴趣,能够在这里了解更多。
如今是时候巩固下你新学到的知识。
NodeList
。请写一个函数,它接收一个 CSS 选择器,而后返回一个选择到的 DOM 节点数组。null
或 undefined
,那就新建一个 object
。示例:set.call( {name: "jay"}, {age: 10, email: '[[email protected]](/cdn-cgi/l/email-protection)'}); // return {name: "jay", age: 10, email: '[[email protected]](/cdn-cgi/l/email-protection)'}
。apply 就是接受数组版本的 call。因而当使用 apply
时,多联想下数组。
将一个方法应用(apply)到一个数组上。
我用这句话来记住它,并且还挺管用。apply 为你的现有堆积的军火库又添加了同样利器,增长了不少新的可能,你很快就能体会到这一点。
当你要处理参数数量动态变化的场景,用 apply 吧。将一系列数据转化为数组并用上 apply 能让你写出更好用和更具弹性的代码,会让你的工做更轻松。
Math.min 和 max
都是能够接受多个参数并返回最小值和最大值的函数。除了直接传 n 个参数,你也能够将这 n 个参数放到一个数组里而后借助 apply
将它传到 min 函数里。
Math.min(1,2,3,4); // 返回 1 Math.min([1,2,3,4]); // 返回 NaN。只接受数字 Math.min.apply(null, [1,2,3,4]); // 返回 1
看晕了吗?若是真晕了,那我来解释下。使用 apply 时咱们要传一个数组由于它须要数组做为第二个参数。而下面
Math.min.apply(null, [1,2,3,4]); // 返回 1
作的事情基本等同于
Math.min(1,2,3,4); // 返回 1
这就是我想指出来的 apply 的神奇之处。它和 call
工做原理,不过咱们只要传给它一个数组而不是 n 个参数。很好玩对吧?桥豆麻袋,这是否意味着 Math.min.call(null, 1,2,3,4);
执行起来和 Math.min.apply(null, [1,2,3,4]);
同样?
啊,你说对了!看来你已经开始掌握它了
让咱们来看下另外一种用法。
function logArgs() { console.log.apply(console, arguments); } logArgs(1,3,'I am a string', {name: "jay", age: "1337"}, [4,5,6,7]);
没错,你甚至能够传一个类数组对象做为 apply
的第二个参数。很酷对吧?
null
或 undefined
,那就新建一个 object
。示例:set.apply( {name: "jay"}, [{age: 10}]); // 返回 {name: "jay", age: 10}
Math.max
和 min
的函数,不过接收的不是数字而是运算。前两个参数必须是数字
,然后面的参数你要将其转化为一个函数数组。下面提供一个方便你上手理解的示例:function operate() { if (arguments.length < 3) { throw new Error("至少要三个参数"); } if (typeof arguments[0] !== 'number' || typeof arguments[1] !== 'number') { throw new Error("前两个参数必须是数字"); } // 写代码 // 这是一个由函数组成的数组。你能够用 call、apply 或者 bind。但不要直接遍历参数而后直接塞到一个数组里 var args; var result = 0; // 好了,开始吧,祝好运 } function sum(a, b) { return a + b; } function multiply(a,b) { return a * b; } console.log(operate(10, 2, sum, multiply)); // 必须返回 32 -> (10 + 2) + (10 * 2) = 32
假如我上面的解释没能让你释疑,那下面这些额外的资料能够帮你更好地理解 bind 在 JavaScript 里面是怎么运做的。
我还强烈推荐你去学习 JavaScript 原型链,不单是由于里面用到大量的 this
关键词,并且它仍是 JavaScript 实现继承的标准方式。
下面列出一些帮你了解 this
如何使用的书籍:
考虑到 this
关键词已经用到了难以计量的代码中,它是 JavaScript 中咱们不得不聊的话题。
一个优秀的艺术家确定精于工具的使用。做为一个 JavaScript 开发者,怎么用好它的特性是最最重要的。
若是你想看到一些从特定角度对 this
关键词深刻剖析的文章或者更多的代码,请别忘了告诉我。这些可能的角度能够是(但不限于)下面这些:
this
和 new
关键词。this
和 JavaScript 的类。做者:老教授连接:https://juejin.im/post/5aefe76e6fb9a07abc29d4a1来源:掘金著做权归做者全部。商业转载请联系做者得到受权,非商业转载请注明出处。