免费制作网站和网页,珠海seo排名收费,wordpress get_category,佛山优化推广原型与继承 在 JavaScript 中#xff0c;对象有一个特殊的隐藏属性 [[Prototype]]#xff08;如规范中所命名的#xff09;#xff0c;它要么为 null#xff0c;要么就是对另一个对象的引用。该对象被称为“原型。 当我们从 object 中读取一个缺失的属性时#xff0c;Jav…原型与继承 在 JavaScript 中对象有一个特殊的隐藏属性 [[Prototype]]如规范中所命名的它要么为 null要么就是对另一个对象的引用。该对象被称为“原型。 当我们从 object 中读取一个缺失的属性时JavaScript 会自动从原型中获取该属性。在编程中这被称为“原型继承”。 use strict;const user {name: user,age: 18
}
const admin {__proto__: user, // __proto__ 的值可以是对象也可以是 null。而其他的类型都会被忽略。一个对象只能有一个 [[Prototype]]。一个对象不能从其他两个对象获得继承。name: admin,
}
console.log(admin.name); // admin
console.log(admin.age); // 18console.log(admin.__proto__); // { name: user, age: 18 }
console.log(admin.__proto__.__proto__); // [Object: null prototype] {}
console.log(admin.__proto__.__proto__.__proto__); // null
// 获取对象所有的属性名, 包括不可迭代的属性
console.log(Object.getOwnPropertyNames(admin.__proto__.__proto__));
/*
[constructor,__defineGetter__,__defineSetter__,hasOwnProperty,__lookupGetter__,__lookupSetter__,isPrototypeOf,propertyIsEnumerable,toString,valueOf,__proto__,toLocaleString
]
*/
// 只返回自己的 key
console.log(Object.keys(admin)); // [ name ]
// for..in 会遍历自己以及继承的键
for(let key in admin) console.log(key); // name age
// 方法 obj.hasOwnProperty(key)如果 obj 具有自己的非继承的名为 key 的属性则返回 true。
console.log(admin.hasOwnProperty(name)); // true
console.log(admin.hasOwnProperty(age)); // false__proto__ 是 [[Prototype]] 的因历史原因而留下来的 getter/setter 初学者常犯一个普遍的错误就是不知道 __proto__ 和 [[Prototype]] 的区别。 请注意__proto__ 与内部的 [[Prototype]] 不一样。__proto__ 是 [[Prototype]] 的 getter/setter。稍后我们将看到在什么情况下理解它们很重要在建立对 JavaScript 语言的理解时让我们牢记这一点。 __proto__ 属性有点过时了。它的存在是出于历史的原因现代编程语言建议我们应该使用函数 Object.getPrototypeOf/Object.setPrototypeOf 来取代 __proto__ 去 get/set 原型。稍后我们将介绍这些函数。 根据规范__proto__ 必须仅受浏览器环境的支持。但实际上包括服务端在内的所有环境都支持它因此我们使用它是非常安全的。 由于 __proto__ 标记在观感上更加明显所以我们在后面的示例中将使用它。 let user {setName(name){this.name name}
}
let admin {__proto__: user
}
// 即使是调用的继承对象user中的方法, 但是方法中的this依然指向调用者admin
admin.setName(admin);
console.log(admin.name); // admin
console.log(user.name); // undefind我们还记得可以使用诸如 new F() 这样的构造函数来创建一个新对象。 如果 F.prototype 是一个对象那么 new 操作符会使用它为新对象设置 [[Prototype]]。 use strict;MyArray.prototype new Array(); // * 与使用 ** 行, ***行 等效
// Array.prototype Array.prototype // **
function MyArray() {// this.__proto__ new Array(); // ***// this 是一个new出来的具体对象, MyArray 是一个构造函数
}const arr new MyArray();
// MyArray.prototype上的属性方法可直接使用, 未找到会自动向上寻找, 在arr.__proto__上找到constructor方法
console.log(arr.constructor Array); // true
console.log(arr.__proto__.constructor Array); // true
// 调用Array.prototype 上的方法
arr.push(...[1, 2, 3]);
console.log(arr); 每个函数都有 prototype 属性即使我们没有提供它。 默认的 prototype 是一个只有属性 constructor 的对象属性 constructor 指向函数自身。 use strict;function User() {}console.log(Object.getOwnPropertyDescriptors(User.prototype));
/* {constructor: {value: [Function: User],writable: true,enumerable: false,configurable: true}} */
console.log(User.prototype.constructor User); // true
console.log(User.prototype.__proto__.constructor Object); // true
console.log(User.prototype.__proto__.__proto__ null); // true, null没有构造方法const user new User();
console.log(user.__proto__ User.prototype); // true
console.log(user.__proto__.__proto__.__proto__ null); // true, 原型链的尽头是null
// User.prototype 上的属性可直接使用
console.log(user.constructor User); // true在常规对象上prototype 没什么特别的
let user {name: John,prototype: Bla-bla // 这里只是普通的属性
};默认情况下所有函数都有 F.prototype {constructorF}所以我们可以通过访问它的 constructor 属性来获取一个对象的构造器。
use strict;
function User(name){this.name name;
}
// 构造方法应加上关键字new调用
let user1 new User(User1);
console.log(user1);let user2 new User.prototype.constructor(User2);
console.log(user2);let user3 new user1.__proto__.constructor(User3);
console.log(user3);let user4 new user1.constructor(User4);
console.log(user4); // User { name: User4 }User.prototype {}
let user5 new user1.constructor(User5);
console.log(user5); // { name: User5 } 是 new Object(User5)的结果, 继续向上找constructoruser1.__proto__ null // user1.constructor is not a constructor, 如果给{}, 结果是 [String: User6]
let user6 new user1.constructor(User6);
console.log(user6); 内建对象的原型挂载着相关属性和方法
可向prototype上添加自定义方法或属性
// 通过原型查看数组, 字符串等相关的函数(可在浏览器环境下直接使用String.prototype)// console.log(Object.getOwnPropertyDescriptors(Array.prototype));
console.log(Object.getOwnPropertyNames(Array.prototype));
/* [length, constructor, concat,copyWithin, fill, find,findIndex, lastIndexOf, pop,push, reverse, shift,unshift, slice, sort,splice, includes, indexOf,join, keys, entries,values, forEach, filter,flat, flatMap, map,every, some, reduce,reduceRight, toLocaleString, toString,at
] */
// 所有函数或属性名
console.log(Object.getOwnPropertyNames(String.prototype));
/* [length, constructor, anchor,big, blink, bold,charAt, charCodeAt, codePointAt,concat, endsWith, fontcolor,fontsize, fixed, includes,indexOf, italics, lastIndexOf,link, localeCompare, match,matchAll, normalize, padEnd,padStart, repeat, replace,replaceAll, search, slice,small, split, strike,sub, substr, substring,sup, startsWith, toString,trim, trimStart, trimLeft,trimEnd, trimRight, toLocaleLowerCase,toLocaleUpperCase, toLowerCase, toUpperCase,valueOf, at
] */
console.log(Object.getOwnPropertyNames(Number.prototype));
/* [constructor,toExponential,toFixed,toPrecision,toString,valueOf,toLocaleString
] */
console.log(Object.getOwnPropertyNames(Boolean.prototype));
/* [ constructor, toString, valueOf ] */console.log(Object.getOwnPropertyNames(Date.prototype));
/* [constructor, toString, toDateString,toTimeString, toISOString, toUTCString,toGMTString, getDate, setDate,getDay, getFullYear, setFullYear,getHours, setHours, getMilliseconds,setMilliseconds, getMinutes, setMinutes,getMonth, setMonth, getSeconds,setSeconds, getTime, setTime,getTimezoneOffset, getUTCDate, setUTCDate,getUTCDay, getUTCFullYear, setUTCFullYear,getUTCHours, setUTCHours, getUTCMilliseconds,setUTCMilliseconds, getUTCMinutes, setUTCMinutes,getUTCMonth, setUTCMonth, getUTCSeconds,setUTCSeconds, valueOf, getYear,setYear, toJSON, toLocaleString,toLocaleDateString, toLocaleTimeString
] */
console.log(Object.getOwnPropertyNames(Map.prototype));
/* [constructor, get,set, has,delete, clear,entries, forEach,keys, size,values
] */
console.log(Object.getOwnPropertyNames(WeakMap.prototype));
/* [ constructor, delete, get, set, has ] */console.log(Object.getOwnPropertyNames(Function.prototype));
/* [length, name,arguments, caller,constructor, apply,bind, call,toString
] */
console.log(Object.getOwnPropertyNames(Object.prototype));
/* [constructor,__defineGetter__,__defineSetter__,hasOwnProperty,__lookupGetter__,__lookupSetter__,isPrototypeOf,propertyIsEnumerable,toString,valueOf,__proto__,toLocaleString
] */
console.log(Object.getOwnPropertyNames(Object));
/* [length,name,prototype,assign,getOwnPropertyDescriptor,getOwnPropertyDescriptors,getOwnPropertyNames,getOwnPropertySymbols,is,preventExtensions,seal,create,defineProperties,defineProperty,freeze,getPrototypeOf,setPrototypeOf,isExtensible,isFrozen,isSealed,keys,entries,fromEntries,values,hasOwn
] */如果速度很重要就请不要修改已存在的对象的 [[Prototype]] 通常我们只在创建对象的时候设置它一次自那之后不再修改 现代的获取/设置原型的方法有 Object.getPrototypeOf(obj) —— 返回对象 obj 的 [[Prototype]]。Object.setPrototypeOf(obj, proto) —— 将对象 obj 的 [[Prototype]] 设置为 proto。 Object.create(null)这样的对象称为 “very plain” 或 “pure dictionary” 对象因为它们甚至比通常的普通对象plain object{...} 还要简单。 缺点是这样的对象没有任何内建的对象的方法例如 toString use strict;
// 这个对象没有原型[[Prototype]] 是 null
// 创建一个以null为原型的对象, 在obj中, __ptoto__、toString等原本的内建属性和方法不复存在, 只是普通的方法和属性
let obj Object.create(null);console.log(obj.__proto__); // undefined
// console.log(obj.toString()); // TypeError: obj.toString is not a function// 正常的
let obj1 {};
console.log(obj1.__proto__); // [Object: null prototype] {}
console.log(obj1.toString()); // [object Object]