原型链
概念
prototype(原型)是函数的一个属性,它定义了构造函数制造出的对象的公共祖先。通过该构造函数产生的对象,可以继承该原型的属性和方法。 __proto__
(原型链)是对象的一个属性,它指向该对象的原型。通过该对象可以访问原型的属性和方法。
从属关系
prototype(原型)是函数 Function 的一个属性,它指向一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。 __proto__
(原型链)是对象 Object 的一个属性,它指向该对象的原型。通过该对象可以访问原型的属性和方法。 对象的__proto__
保存着对象的构造函数的 prototype。
Function.prototype === Function.__proto__
// true Object.prototype === Object.__proto__
// true Object.__proto__ === Function.prototype
// true Object.__proto__ === Function.__proto__
// true
判断实例对象是否有某个属性,可以使用 hasOwnProperty 方法。 test.hasOwnProperty('name')
判断实例对象原型链上是否有某个属性,可以使用 in 运算符。 test.name in test
constructor -> 实例化对象的构造函数
通过原型判断类型
在 JavaScript 中,我们通常使用typeof
和instanceof
运算符来判断一个变量的类型。然而,这两种方式都有它们的局限性。typeof
只能判断出基本类型,而instanceof
只能判断出对象的类型,并且它依赖于原型链,如果原型链被修改,那么结果可能就不准确了。
如果你想通过原型来判断类型,你可以使用Object.prototype.toString.call()
方法。这个方法会返回一个表示该对象的字符串,格式为[object Type]
,其中Type
是对象的类型。这种方法可以准确判断出所有类型的值,包括null
和undefined
。
例如:
let num = 1;
let str = "hello";
let arr = [1, 2, 3];
let obj = {};
let fun = function () {};
let date = new Date();
let reg = /test/g;
let err = new Error();
console.log(Object.prototype.toString.call(num)); // "[object Number]"
console.log(Object.prototype.toString.call(str)); // "[object String]"
console.log(Object.prototype.toString.call(arr)); // "[object Array]"
console.log(Object.prototype.toString.call(obj)); // "[object Object]"
console.log(Object.prototype.toString.call(fun)); // "[object Function]"
console.log(Object.prototype.toString.call(date)); // "[object Date]"
console.log(Object.prototype.toString.call(reg)); // "[object RegExp]"
console.log(Object.prototype.toString.call(err)); // "[object Error]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call(undefined)); // "[object Undefined]"
这样,你就可以通过原型来判断 JavaScript 中的类型了。
继承与共享属性
在 JavaScript 中,原型(prototype)是一种非常强大的机制,它用于实现继承和共享属性。以下是原型的一些主要用途:
实现继承:在 JavaScript 中,你可以使用原型来实现继承。这是通过将一个对象的原型设置为另一个对象来实现的。这样,当你尝试访问一个对象的属性时,如果这个对象本身没有这个属性,那么 JavaScript 就会去它的原型对象中查找。
javascriptfunction Person(name) { this.name = name; } Person.prototype.sayHello = function () { console.log("Hello, I'm " + this.name); }; var alice = new Person("Alice"); alice.sayHello(); // "Hello, I'm Alice"
在这个例子中,
sayHello
方法是定义在Person
的原型上的,所有的Person
实例都可以访问到这个方法。共享属性:原型可以用来共享属性。当你在一个对象的原型上定义一个属性时,所有的这个对象的实例都可以访问这个属性。
javascriptfunction Team(name) { this.name = name; } Team.prototype.members = []; var team1 = new Team("Team 1"); var team2 = new Team("Team 2"); team1.members.push("Alice"); console.log(team2.members); // ["Alice"]
在这个例子中,
members
属性是定义在Team
的原型上的,所以所有的Team
实例都共享这个属性。扩展内置类型:你可以使用原型来扩展 JavaScript 的内置类型,比如
Array
、String
等。这是通过在内置类型的原型上添加方法来实现的。javascriptArray.prototype.first = function () { return this[0]; }; var arr = [1, 2, 3]; console.log(arr.first()); // 1
在这个例子中,我们在
Array
的原型上添加了一个first
方法,所有的数组都可以使用这个方法。
请注意,虽然原型是一个非常强大的工具,但是也需要谨慎使用。在原型上添加属性或方法会影响所有的实例,如果不小心,可能会导致一些难以预料的问题。