导航
new Object
const obj = new Object()
obj.name = 'Lance'
const obj = { name: 'Lance' }
function createObj(name) {
const obj = new Object()
obj.name = name
return obj
}
const obj = createObj('Lance')
function Person(name) {
this.name = name
}
const person = new Person('Lance')
hasOwnProperty
hasOwnProperty返回一个布尔值,指出一个对象是否具有指定名称的属性。此方法不会检查该对象的原型链中是否具有该属性;该属性必须是对象本身的一个成员。
使用方法: object.hasOwnProperty(proName) 其中参数object是必选项。一个对象的实例。 proName是必选项。一个属性名称的字符串值。 如果 object 具有指定名称的属性,那么JavaScript中hasOwnProperty函数方法返回 true,反之则返回 false。
只要右边变量的
prototype
在左边变量的原型链上即可。
思路
proto = proto.__proto__
,沿着原型链一直向上查找)__proto__
上找到了当前类的原型prototype
,则返回 true
Object.prototype.__proto__ == null
,Object的基类(null)上面都没找到,则返回 falsefunction myInstanceof(obj, Func) {
let __proto__ = obj.__proto__; // 拿到对象原型
let prototype = Func.prototype; // 拿到构造函数原型
while (true) {
if (__proto__ === null) { // 退出条件: 找到了 Object的基类 Object.prototype.__proto__
return false;
}
if (__proto__ === prototype) { // 在对象的原型链上找到了构造函数
return true;
}
__proto__ = __proto__.__proto__; // 沿着原型链 __proto__ 一层一层向上查找
}
}
优化版 (处理兼容问题)
Object.getPrototypeOf ( ):用来获取某个实例对象的原型(内部[[prototype]]属性的值,包含proto属性)
function myInstanceof(obj, Func) {
let __proto__ = Object.getPrototypeOf(obj);
let prototype = Func.prototype;
while (true) {
if (__proto__ === null) {
return false;
}
if (__proto__ === prototype) {
return true;
}
__proto__ = Object.getPrototypeOf(__proto__);
}
}
分析一下 new 的整个过程:
function _new(fn, ...args) {
const obj = Object.create(fn.prototype)
const ret = fn.apply(obj, args)
return ret instanceof Object ? ret : obj
}
// 测试
function Person(name, age) {
this.name = name
this.age = age
this.sayHi = function() {}
}
Person.prototype.run = function() {}
console.log(_new(Person, 'Lance', 19))
console.log(new Person('Jerry', 20))
this === window ? 'browser' : 'node';
通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中
JSON.parse(JSON.stringify())
Object.assgin
// 不解决循环引用
function deepClone(obj) {
// 处理 null 或者 undefined
if (obj === null || typeof obj !== 'object') {
return obj;
}
// 处理数组
if (Array.isArray(obj)) {
var arrCopy = [];
for (var i = 0; i < obj.length; i++) {
arrCopy[i] = deepClone(obj[i]);
}
return arrCopy;
}
// 处理普通对象
var objCopy = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
objCopy[key] = deepClone(obj[key]);
}
}
return objCopy;
}
var test1 = {};
var test2 = {};
test1.test2 = test2;
test2.test1 = test1;
function deepClone(source, hashMap = new WeakMap()) {
if (source == undefined || typeof source !== 'object') {
return source;
}
if (source instanceof Date) {
return new Date(source);
}
if (source instanceof RegExp) {
return new RepExp(source);
}
const hasItem = hashMap.get(source);
if (hasItem) return hasItem;
const target = new source.constructor();
hashMap.set(source, target);
for (const key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = deepClone(source[key], hashMap);
}
}
return target;
}
console.log(deepClone(test2));
value
:给target[key]设置初始值get
:调用target[key]时触发set
:设置target[key]时触发writable
:默认false,为true时此属性才能被赋值运算符修改enumerable
:默认false,为true时此属性才能被枚举configurable
:默认为false,为true时此属性的描述符才能被修改,才能被删除// ES5
function People(name, age) {
this.name = name;
this.age = age;
}
let Singleton = function(Fn) {
let _instance = null;
return function(...args) {
if (_instance) return _instance;
return _instance = new Fn(...args);
}
}
let peopleSingleton = Singleton(People);
let ming = new peopleSingleton('ming', 18);
let fang = new peopleSingleton('fang', 18);
console.log(ming, fang);
// ES6
class People {
constructor(name, age) {
if (typeof People._instance === 'object') return People._instance;
this.name = name;
this.age = age;
return People._instance = this;
}
}
let ming = new People('ming', 20);
let fang = new People('fang', 19);
console.log(ming, fang);
const obj = {
a: 1,
b: 2,
}
obj.c = obj
// isHasCircle函数, 存在环输出true,不存在的话输出false
isHasCircle(obj)
function isHasCircle(obj) {
let hasCircle = false; // 是否循环
const map = new Map(); // map存对象
function loop(obj) {
const keys = Object.keys(obj)
keys.forEach(key => {
const value = obj[key]
if (typeof value == 'object' && value !== null) {
if (map.has(value)) { // 如果有,判定有循环,return退出迭代
hasCircle = true
return
} else { // 如果没有,添加元素进map,继续递归元素
map.set(value, value)
loop(value)
}
}
})
}
loop(obj)
return hasCircle
}
JSON.stringify()将值转换为相应的JSON格式:
JSON.stringify(function(){})
or JSON.stringify(undefined)
.Professor.prototype = {
name: 'Mr.Zhang',
tSkill: 'Java'
}
function Professor() {}
var professor = new Professor(); // 让子类 prototype 等于 父类的实例化对象
Teacher.prototype = professor;
function Teacher() {
this.name = 'Mr.Wang';
this.mSkill = 'JS';
}
var teacher = new Teacher();
Student.prototype = teacher;
function Student() {
this.name = 'Mr.Li';
this.pSkill = 'HTML';
}
var student = new Student();
console.log(student);
Teacher.prototype.wife = 'Ms.Liu';
function Teacher(name, mSkill) {
this.name = name;
this.mSkill = mSkill;
}
function Student(name, mSkill, age, major) {
Teacher.apply(this, [name, mSkill]);
this.age = age;
this.major = major;
}
var student = new Student('Mr.B', 'JS', 18, 'Computer');
console.log(student);
function Teacher() {
this.name = 'Mr.Wang';
this.mSkill = 'JS';
}
Teacher.prototype = {
pSkill: 'JQ'
}
var teacher = new Teacher();
Student.prototype = Teacher.prototype;
function Student() {
this.name = 'Mr.Li';
}
var student = new Student();
Student.prototype.name = 'student';
console.log(student);
console.log(Teacher.prototype);
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function() {
console.log("sayHi");
}
}
Person.prototype.eat = function() {
console.log("eat");
}
function Student(name, age, score) {
Person.call(this, name, age);
this.score = score;
this.study = function() {
console.log("study");
}
}
var inherit = (function () {
function Buffer() {}
return function (Target, Origin) {
Buffer.prototype = Origin.prototype;
Target.prototype = new Buffer();
// 还原构造器
Target.prototype.constructor = Target;
// 指定继承源
Target.prototype.super_class = Origin;
}
})();
inherit(Student, Person);
var stu1 = new Student("Lance", 19, 100);
console.dir(stu1);
var obj1 = Object.create(null);
obj1.a = 1;
var obj2 = Object.create(obj1);
obj2.b = 2;
console.log(obj2.__proto__); // ?
原型存在在原型链上,但现在链不存在了(就是最终到达 Object.prototype 的这个链儿 在 obj1 这断掉了)
所以只要原型链断掉,往回倒得所有对象就都无法通过 自己.__proto__
找到原型,为 undefined(也就是指针不指向任何原型了,就是 undefined 了)
__proto__
是原型链的指针,原型链都被破坏了,这个指针也断了
__proto__
是 Object 的 属性
// 第一种
const a = {
i: 0,
toString() {
return ++this.i
}
}
console.log(a == 1 && a == 2 && a == 3) // true
// 第二种
const a = [1, 2, 3]
a.join = a.shift
console.log(a == 1 && a == 2 && a == 3) // true
// 第三种
let i = 0
Object.defineProperty(global, 'a', {
get() {
return ++i
}
})
console.log(a == 1 && a == 2 && a == 3) // true
_ + _
为 'ab'_ + _ + _
为 'abc'Object.defineProperty(window, '_', {
get() {
this.curCharCode = this.curCharCode || 'a'.charCodeAt(0); // 找到起始ascii位
this.curChar = String.fromCharCode(this.curCharCode); // 赋值给要返回的值
if (this.curCharCode >= 'a'.charCodeAt(0) + 26) return ''; // 一旦大于等于26 就返回空字符串
this.curCharCode++; // 起始位自增
return this.curChar;
}
})
console.log(_ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _ + _);
LazyMan('Tony');
// Hi I am Tony
LazyMan('Tony').sleep(10).eat('lunch');
// Hi I am Tony
// 等待了10秒...
// I am eating lunch
LazyMan('Tony').eat('lunch').sleep(10).eat('dinner');
// Hi I am Tony
// I am eating lunch
// 等待了10秒...
// I am eating diner
LazyMan('Tony').eat('lunch').eat('dinner').sleepFirst(5).sleep(10).eat('junk food');
// Hi I am Tony
// 等待了5秒...
// I am eating lunch
// I am eating dinner
// 等待了10秒...
// I am eating junk food
答案:
class LazyManClass {
constructor (name) {
this.name = name
this.task = []
console.log('Hi I am', name)
**setTimeout(() => {
this.next()
}, 0)**
}
eat (str) {
this.task.push(() => {
console.log('I am eating', str)
this.next()
})
return this
}
sleep (n) {
this.task.push(() => {
setTimeout(() => {
console.log('等待了' + n + 's')
this.next()
}, n * 1000)
})
return this
}
sleepFirst (n) {
this.task.unshift(() => {
setTimeout(() => {
console.log('等待了' + n + 's')
this.next()
}, n * 1000)
})
return this
}
next () {
let fn = this.task.shift()
fn && fn()
}
};
let LazyMan = function (name) {
return new LazyManClass(name)
};
解析:
这道题的关键点有如下几个:
题目来源:Daily-Interview-Question 第56题
const obj = {
a: {
b: 1,
c: 2,
d: { e: 5 },
},
b: [1, 3, { a: 2, b: 3 }],
c: 3,
d: []
}
/*
{
'a.b': 1,
'a.c': 2,
'a.d.e': 5,
'b[0]': 1,
'b[1]': 3,
'b[2].a': 2,
'b[2].b': 3
c: 3,
d: []
}
*/
function flatObj(obj) {
let ret = {};
function walk(key, value) {
if (typeof value === 'object' && value !== null) { // 是对象时
if (Array.isArray(value)) { // 是数组时
value.forEach((item, idx) => {
walk(`${key}[${idx}]`, item);
});
if (value.length === 0) ret[key] = [];
} else { // 是对象时
Object.entries(value).forEach(([k, value]) => {
walk(`${key}.${k}`, value);
});
if (Object.entries(value).length === 0) ret[key] = {};
}
} else { // 不是对象时
ret[key] = value;
}
}
// 第一次遍历 walk
Object.entries(obj).forEach(([key, value]) => walk(key, value));
return ret;
}
console.log(flatObj(obj));