首页 > 编程 > JavaScript > 正文

JavaScript 原型链/Function/Object/属性搜索原则/instanceof

2019-11-06 06:07:23
字体:
来源:转载
供稿:网友

1. 原型链(1)对象的原型链绘制原型链的结构(三角形)[] -> Array.PRototype -> Object.prototype -> nullp -> Person.prototype -> Object.prototype -> null{} -> Object.prototype -> null原型式继承:① 原型式继承就是原型中提供的成员,我们的实例对象可以直接使用,好像是自己的一样② 所谓的操作原型式继承就是在对原型链做增加、删除、修改的操作
//如果有 animalfunction Person() {}Person.prototype = animal;var p = new Person();//原型链(相当于在原来的链中增加了一节):p -> Person.prototype(其实是animal) -> Animal.prototype -> Object.prototype(2)函数的原型链绘制原型链的结构(3)完整原型链结合对象的原型链和函数的原型链,将其绘制到一起

2. Function

Function 是函数的构造函数(函数的constructor属性就等于Function)借助这个理论可以绘制函数的对象原型链(三角形)

3. 利用 Function 构建函数

定义一个函数需要有:① 参数② 函数体③ 返回值 这三个东西本质上是代码,js允许将这些代码以字符串的形式放到 Function 中,来构建函数。语法:
var func = new Function( 参数1, 参数2, ..., 函数体 )例:设计一个函数,求两个数字的和
var sum = new Function( 'a', 'b', 'return a+b;' );函数体太多内容时,一般来说使用字符串拼接 + 折行显示。为了解决麻烦,引入ES6中的可换行字符串,数字键左边的左撇号。第三种方法,在页面添加一个标签
<script type="text/template" id="code">    函数体</script>document.createElementFragment应用:所见即所得的编辑器

4. 绘制函数的原型链结构

函数的构造函数是 FunctionFunction 是什么数据类型?函数结论:Function 是 Function 的构造函数① Function.prototype 是原型对象,Function 就继承自该原型对象② Function 是 Function 的实例Function instanceof Function 为 true推论:Function instanceof Object 为 trueObject instanceof Function 为 trueFunction 也是函数,因此 Function 是 Function 的实例这是原型链中唯一的特例(两个对象构成三角形关系)因此,Function 的 .prototype 与 .__proto__ 指向同一个对象一般的函数不是这样function Person() {}1) Person.prototype 是用于描述实例对象的, 表示 new Person() 所继承的对象. 2) Person.__proto__ 是用于描述 Person 这个函数作为对象来说是 Function 的实例. 是 Function.prototype. 因此一般的函数, 这两个属性不是同一个对象.Function -> Function.prototype -> Object.prototype -> null例如:希望让js中的所有函数都有 inherit 方法,来实现派生Function.prototype.inherit = function() {}Object.prototype.inherit = function() {}

5. __proto__

作用:让实例对象可以访问到该原型对象早期是无法直接访问的,如果早期需要访问,用 obj.constructor.prototype这样不方便调试,很麻烦,因此在火狐中率先引入 __proto__ 属性,用于让对象直接访问其原型。由于当时是非标准属性,因此使用__作为前后缀。但是由于非常好用,今天的浏览器基本都实现了该属性,但依旧没有标准化(IE8不支持)。因此在开发时,不建议用,也不可以使用该属性。调试原型链结构:obj.__protp__.__proto__.__proto__.__proto__因此在实际开发中,使用 __proto__ 只是用于调试查看,即只用其读的特性。以前的结论:① 只有函数有 prototype 属性② 只有实例对象有 __proto__ 属性今天的结论:函数也是对象,函数也有 __proto__ 属性① 函数有 prototype 属性,该属性指向原型,该原型被函数的实例对象所继承② 函数有 __proto__ 属性,该属性指向原型,该函数继承自该原型③ 函数的 __proto__ 就是 Function.prototype,Function.__proto__ 就是 Function.prototype

6. Object 本身就是一个构造函数

function Person() { }// Object 与 Person 是等同地位的就像人是由基因决定的,无论是父亲还是儿子都有基因基因就好比构造函数,决定对象有什么成员,也就是对象长什么样子结论:① 对象应该都有原型② 实例对象继承自 构造函数.prototype③ 原型对象也有继承的关系④ 只有原型中有 constructor,constructor 决定了原型的名字如果 constructor 是 AAA, 那么 这个原型就是 AAA.prototype到此我们得到对象的原型链结构1) [ ]    [ ] -> Array.prototype -> Object.prototype -> null2) p: Person    p -> Person.prototype -> Object.prototype -> null3) { }    { } -> Object.prototype -> null结合原型式继承. 什么是原型式继承? 怎么操作原型式继承?1) 原型式继承就是 原型中提供的成员, 我们的实例对象可以直接使用, 好像是自己的一样.2) 所谓的操作原型式继承就是在 对原型链做增加, 删除, 修改的操作.
//如果有 animalfunction Person () {}Person.prototype = animal;var p = new Person();...//原型链://p -> Person.prototype( 其实是 animal ) -> Animal.prototype -> Object.prototype -> null

7. 字面量的原型链

所谓的字面量就是在代码中的写出来以后有数据、有大小、有类型等具体的数据。常见的字面量有:数字    1,2,123, ...布尔值    true,false字符串    'xxxxxx'对象    { },注意有时需要使用( { } )数组    [ ]函数    function() { }正则表达式    /.+/字面量中,凡是引用类型的都有对应的构造函数,因此原型链的绘制就简单了。8. 属性搜索原则错误的结论:如果一个对象中没有对应的方法,但是其原型中提供了该方法,该对象可以直接使用原型中的方法,就好像是自己的方法一样。所谓的属性搜索原则是说,对象在访问某一个成员的时候,采用的访问规则① 首先在当前对象中查找是否有对应的成员(在自己的代码结构中找)② 如果有,则使用该成员,并停止查找,如果没有,则到其原型对象中查找对应的成员③ 如果其原型中有该成员,则使用,并停止查找,否则继续往原型的原型中查找④ 如此往复⑤ 直到 Object.prototype 中,如果还没有对应的成员,则返回 undefined访问依照就近原则

9. 原型成员的读写

在读取数据的时候,如果当前对象没有该数据,原型中提供了该数据,那么可以直接访问该数据。但是,如果是修改属性,不会对原型中的数据造成任何影响,只会在当前对象中新创建一个该成员,再次读取该成员时,就不再走原型上的数据了。

10. instanceof 运算符

语法:object(要检测的对象) instanceof constructor(某个构造函数)  -> boolean含义:检测 constructor.prototype 是否存在于 object 的原型链上,即一个对象在其原型链中是否存在一个构造函数的 prototype 属性案例1:
function Person() {}var p = new Person();p instanceof Person   // true//p 的原型链://p -> Person.prototype -> Object.prototype -> null案例2:
function Person() {}var p1 = new Person();Person.prototype = {};var p2 = new Person();console.log( p1 instanceof Person );//falseconsole.log( p2 instanceof Person );//true//分析原型链://p1 -> Person.prototype(原始的类型) -> Object.prototype -> null//p2 -> Person.prototype( { } ) -> Object.prototype -> null//现在 Person.prototype 是 { }//p1 instanceof Person 表示检测 { } 是否在 p1 的原型链中 -> false//p2 instanceof Person 表示检测 { } 是否在 p2 的原型链中 -> true案例3:
console.log(Function instanceof Object);//true//Object.prototype 是否在 Function 的原型链中console.log(Function instanceof Function);//true//Function.prototype 是否在 Function 的原型链中console.log(Object instanceof Object);//true//Object.prototype 是否在 Object 的原型链中console.log(Object instanceof Function);//true//Function.prototype 是否在 Object 的原型链中//Object -> Function.prototype -> Object.prototype -> null    Object、Function、Array 等等都是构造函数,都是函数 => 而所有函数都是构造函数 Function 的实例 => 从原型链机制来说,所有函数都能通过原型链找到创建他们的构造函数 Function 的构造原型 Function.prototype 对象=> Object instanceof Function 的结果为 true    又因为 Function.prototype 是一个对象=> Function.prototype 的构造函数是 Object=> 从原型链机制来说,所有对象都能通过原型链找到创建它们的构造函数 Object 的构造原型 Object.prototype 对象=> Function instanceof Object 的结果为 true    Function 是构造函数=> Function 是函数对象=> 函数对象都是由 Function 构造函数创建而来的,从原型链机制来说,函数对象的原型链中存在 Function.prototype => Function.prototype 在构造函数 Function 的原型链中被查到=> Function instanceof Function 的结果为 true结论:在 js 中,一切皆对象,它们全部继承自 Object,或者说所有对象的原型链的根节点都是 Object.prototypejs原型链-jk.png

11. Object.prototype 的常用成员

(1)hasOwnProperty

语法:对象.hasOwnProperty( '属性名称' ) -> boolean含义:判断某个属性是否是当前对象提供,而不是原型提供的作用:一般在写混入的时候会使用for(var k in obj){    //只混入当前对象的属性    if(obj.hasOwnProperty(k)){        dist[k] = obj[k];    }}

(2)isPrototypeOf

语法:对象A.isPrototypeOf( 对象B ) -> boolean含义:判断 对象A 是不是 对象B 的原型(实质上是判断对象A是否在对象B的原型链中)

(3)prototypeIsEnumerable

语法:对象A.prototypeIsEnumerable( '属性名称' ) -> boolean含义:判断当前对象是否提供对应的属性,同时该属性可枚举在 js 中一般添加的成员都是可枚举的(所谓的可枚举就是利用 for in 可以遍历出来)在 ES5 之前,所有的自定义属性都是可枚举的,是无法控制的。因此该方法很少使用。在 ES5 之后,引入了 Object.definedPrototype 等方法,允许用户定义不可枚举的属性。

(4)valueOf

将对象转换成基本类型(实现的不好,平时不会用,都是自己实现该方法去转换)内部的实现就是 return this,把自己返回了,并没有实现功能,没什么用处

(5)toString

将对象转换成字符串(实现的不好,平时不会用,都是自己实现该方法去转换)
console.log(s.toString());//[object Object](假设s是个对象)console.log([].toString());//默认将数组元素用逗号连接,因此会打印空//数组自己有 toString 方法

(6)toLocaleString

将对象转换成本地字符串(实现的不好,平时不会用,都是自己实现该方法去转换)例:计算机毫秒数从1970年开始算


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表