题目来源及自己的思路
最近在学习JS面向对象以及原型模式的过程中,有一些疑惑。
由《JS中new操作符做了什么?》--Crushdada's shimo Notes 想到的--
function create(Con, ...args){ //Con即要new的构造函数
// 创建一个空的对象
let obj = Object.create(null);
// 将空对象指向构造函数的原型链
Object.setPrototypeOf(obj, Con.prototype);
// obj绑定到构造函数上,便可以访问构造函数中的属性,即obj.Con(args)
let result = Con.apply(obj, args);
// 如果返回的result是一个对象则返回
// 否则new方法失效,返回obj空对象
return result instanceof Object ? result : obj;
}
在我整理的该篇中,new实现机制的最后一部(忽略使用instance容错那一步),是使用apply方法,然后就能通过obj对象就能够访问构造函数Con的属性和方法
在我以往的理解中,该方法是令构造函数的this指向空对象,那么--
函数内的this是函数的内置对象吗?这个指向是赋值吗?将构造函数的this对象赋给那个空对象?
然后百度的过程中,又看到一个JS类继承的例子:
var father = function() {
this.age = 52;
this.say = function() {
alert('hello i am '+ this.name ' and i am '+this.age + 'years old');
}
}
var child = function() {
this.name = 'bill';
father.call(this);
}
var man = new child();
man.say();
在最后一条语句man.say()的整个调用过程中,让我们把new关键字内部实现也分析一下来看,它最后会返回一个实例对象,然后,这个实例对象被赋给了man。
个人思考
当我们通过man.say()调用say方法,发生了什么?this是关键字吗?还是函数的内置对象?
很感谢边城的解答,下面总结、纠错和启发一下
- 我之前对apply有误解, 因为百度上都一直在强调改变this指向,让我太过于执着于它本身了,其实应该这样形容这个方法:在调用函数时,重定义this的指向
2.其次,this在apply中的表现,可以当做引用 - 那么,以上代码理解起来就很简单了,执行new 语句的过程如下--
首先,new关键字内部执行到-- let result = child.apply(man, null);
会调用child函数,然后将其中的this直接换成man,就像这样↓
var child = function() {
man.name = 'bill';
father.call(man);
}
var man = new child();
man.say();
4.然后,执行到了call方法,同理,执行father方法并将其中的this换成man--
var father = function() {
man.age = 52;
man.say = function() {
alert('xxx');
}
}
5.然后,man对象已经存在那些属性和方法了,因此直接调用man.say()即可
可能这就是原型继承吧...
为了证实,我们可以打印一下:
未能解决的疑问
已经了解到this在apply方法使用中扮演的角色就像是引用,函数中的this.xx就像是预留给对象来apply似的,以此实现继承。
但是--
MDN对this有这样的两种描述--
1.“函数的 this 关键字”
2.它的值是--“当前执行上下文的一个属性”
以及:为什么我们能直接这样写--this.name = “Crushdada”;
这不是对象属性的声明方式吗?由此--
this本身到底是什么东西?是和new一样被封装的函数吗?
在 OOP (Object Oriented Programming) 中
this
表示对象自身,虽然代码是写在“类”里,但是this
要实例化的时候才会产生,表示的是当前实例对象本身 —— 这原本就没有什么逻辑,就是个规定,唯一有点逻辑的就是语义this
就表示“自己”。JavaScript 不是“经典”的 OOP,而是基于原型模式的 OOP,所以和“经典”OOP 有一点点区别。JS 的对象是通过构造函数来产生,而构造函数和普通函数本质没有区别,再加上 JS 对
this
的定义非常灵活(根据调用者、bind
、apply/call
等不同情况有不同的this
指向,也就是“上下文的一个属性”)所以在 JS 中需要理解的不是this
是什么,而是this
引用什么(对 JS 的对象来说 ,都变量/属性都是引用),或者说得形象一点,“指向”什么。它当然是指向一个对象,就如同你理解的在执行期将
this
指向了man
。既然是一个对象,它就可以像普通对象一样使用,比如直接通过赋值扩展属性:this.blabla = "lalalala"
。至于new
,就如同你一开始给的那一段代码,它只是凭空产生了一个对象,然后将它和构造函数之间建立正确的联系。首先,现在写 JS 代码,尽量使用 ES6 以后的新语法,关于类、继承之类的处理,新语法简单明了还不容易出错,比如
继承如果要用 ES5 的原型模式来实现,还真是需要花些周折(代码不写了,有兴趣可以搜)
我猜你没明白
Con.apply(obj, args);
这是在干什么。你可以查一下Function.prototype.apply
和.call
的参考文档,他们的第一个参数都是强制给予函数调用的的this
指向假如这个
Con
是传入的下面这个函数直接调用
SomeClass()
,在非 strict (严格)模式下,是给 global 对象(比如浏览器环境的window
)赋予一个hello
属性。在 strict 模式下,this
是undefined
,这句话会报错。但是如果调用的时候强制给予this
对象,比如ES5 中构造函数首先是一个函数,它在使用
new
调用的时候才称为构造函数。而new
的时候正如你题中的代码那样,是先产生一个对象,再把它绑定给函数作为this
,执行函数中的代码。好了说了这么多,仍然只是“浅析”,建议你看看:JavaScript 的 this 指向问题深度解析