翻译自:What’s the deal with Object.prototype.hasOwnProperty.call()?
你一定在他人的代码或者某个库中见过下面的代码:
Object.prototype.hasOwnProperty.call(objRef, 'propName');
现在我们来看下这段代码到底什么意思。
在弄清楚的过程中,我们会依次理解下面几件事:
Object.prototype
是什么?- 一个对象在没有定义该函数,在对象的原型链中也没有定义该函数时,为什么可以借调使用该函数?
- 为什么我们在
Object
的prototype
上调用hasOwnProperty
,而不是直接在objRef
实例本身上调用?
好吧,让我们开始吧。
1. Object.prototype
Prototypal inheritance 是JavaScript
最主要的特性之一,它允许对象从它的原型中继承方法和属性。你可以把原型当成一个模板。
让我们看个例子:
var obj = {name: 'aman'}
obj.hasOwnProperty(‘name’) // returns true
正如你所见,我们并没有在obj
上定义hasOwnProperty
,但是我们可以成功调用它,这是怎么回事?
这是因为原型继承和原型链的机制起作用了,让我们继续深入。
当我们创建字面量对象obj
时,它的原型(prototype
)被设定为了Object.prototype,我们可以通过下面的代码验证:
Object.getPrototypeof(obj) === Object.prototype // returns true
obj.__proto__ === Object.prototype // returns true
[[Prototype]]
表明了对象之间的继承关系,在我们的例子中,即obj
和Object.prototype
之间的关系。
原型链长这样:
// Prototype chain
obj —-> Object.prototype ——> null
因此当我们调用hasOwnProperty()
方法时,编译器在obj
上找不到该方法,就向上找(原型链上找),在Object.prototype
上找到了该方法。
此外,我们可以通过Object.setPrototypeOf() 或者Object.create(),自己设定或者重新配置对象的原型。
看下这个例子:
var person = {name: 'peter'};
var PersonPrototype = {getName: function(){ return this.name; }};
// Setting person's prototype
Object.setPrototypeOf(person, PersonPrototype);
// Trying to access getName() method will cause a prototype chain lookup (aka prototype delegation)
// and finds it on PersonPrototype.
person.getName(); // 'peter'
2. 函数借用
假如我们有一个函数和一个对象:
function sayHello() { console.log(`Greetings ${this.name}`) }
var a = {name: 'peter'};
我们怎样做才能让a
调用函数sayHellow
并且传入a
的名字peter
呢?我们并不想让a
去实现函数sayHello
,也不想让函数sayHellow
出现在a
的原型链上。
答案就是通过Function.prototype上的call
或apply
方法。
在JavaScript
中,我们创建的每个函数都继承了Function.prototype,正如上面我们介绍的原型链一样,我们可以在所有函数对象上调用call
方法。
call method 的语法如下:
// 'call' method is available on Function.prototype
func.call(objRef, ...args);
第一个参数是想要借用这个函数的对象,后面跟着函数的剩下的参数列表。
因此,想要借用函数sayHellow
,我们需要做的就是将a
作为参数传入sayHellow.call
方法:
sayHello.call(a); // Greetings peter
3. Object.prototype.hasOwnProperty vs instance.hasOwnProperty
在对原型继承和函数借用进行了简单介绍后,是时候弄清楚为什么我们在Object.prototype
上调用hasOwnProperty
而不是在实例本身上调用了。
正如我们上面介绍的那样,我们可以自己配置对象的原型链,一种方式就是在创建对象实例的时候使用 Object.create():
// Object.create() accepts an argument which becomes
// the prototype for newly created object.
var a = Object.create(null); // Setting `null` as prototype for 'a'.
// Adding a 'name' property on the instance
a.name = 'peter';
// Using `hasOwnProperty` method would cause an error
a.hasOwnProperty('name'); //
标签:函数,Object,原型,hasOwnProperty,call,prototype
From: https://www.cnblogs.com/lhjc/p/17901246.html