for of 和 for in
- for of遍历值,for in遍历下标
- for in遍历出来的下标类型是string
- for in可以根据原型链遍历实例对象的属性名
- for of不能遍历对象。因为能够被for of正常遍历的数据类型都需要实现一个遍历器Iterator。而数组、字符串、Set、Map结构,早就内置好了Iterator(迭代器),它们的原型中都有一个Symbol.iterator方法,而Object对象并没有实现这个接口,使得它无法被for of遍历。可以在Object原型上声明Symbol.interator方法,代码在下面
//对数组
let arr = ['a','b','c']
for(let index in arr){
console.log(index, typeof index)
}
//0 string
//1 string
//2 string
for(let value of arr){
console.log(value)
}
//1 2 3
let arr = ["a", "b", "c"];
arr.name = "arr";
arr.getName = function () {
return this.name;
};
//实例对象的隐式原型=构造函数的显式原型
arr.__proto__.constructor.prototype.sayHello = function () {
return "hello";
};
arr.__proto__.constructor.prototype.parentName = "say uncle";
for (let i in arr) {
if (arr.hasOwnProperty(i)) {
console.log("ownProperty", i);
// '0', '1', '2', 'name', 'getName'
} else {
console.log("not ownProperty", i);
// 'sayHello', 'parentName'
}
}
//hasOwnProperty():判断对象自身是否有这个属性
//给Object添加迭代函数
Object.prototype[Symbol.iterator] = function () {
let _this = this;//this是进行迭代循环的obj
let index = 0;//用来判断是否结束迭代的依据
let length = Object.keys(_this).length;
return {
//done为true时结束迭代,done为false时再调用next方法
next: () => {
let value = _this[Object.keys(_this)[index]];//Object.keys获取对象的键值再放到数组里面
let done = index >= length;
index++;
return { value, done };
},
};
};
//Object的其他两个方法
Object.defineProperty(obj,props)//根据props中提供的键值对,定义或修改obj中的键值对,返回的是修改后的obj,不是一个新对象
Object.getOwnPropertyDescriptors(obj)//获取obj的可描述性属性。
//返回格式:{key:{value: , configurable: false, enumerable: false, get: ƒ (), set: ƒ (data)}}
//configurable决定了能否删除改属性,enumerable决定该属性能否枚举
call apply bind
- 调用形式:
func.call(newThis, args1, args2...)
;func.apply(newThis, [args1, args2...])
;func.bind(newThis)(args1, args2...)
- 返回值: func.call和func.apply返回值就是函数func的返回值,func.bind(newThis)返回值是一个新函数
- 手写实现
实现apply()
Function.prototype.MyApply = function(context, argsArr){
//判断调用MyApply的是否是一个函数
if (!(typeof this === "function")) {
throw new TypeError(`${this} is not a function`);
}
//传递的参数不是数组的情况下 报错
if (!Array.isArray(argsArr)) {
throw new TypeError("CreateListFromArrayLike called on non-object");
}
//其他情况下 开始包装新的上下文
context = Object(context || window);
//要改变新的this 就要用context调用this方法 所以要把this方法放到context的属性上让context调用
const symbolFunc = Symbol(); //不可重复的变量
context.symbolFunc = this;
const result = context.symbolFunc(...argsArr);
delete context.symbolFunc;
return result;
};
实现call()
Function.prototype.MyCall = function(context, ...args){
//判断调用MyApply的是否是一个函数
if (!(typeof this === "function")) {
throw new TypeError(`${this} is not a function`);
}
//其他情况下 开始包装新的上下文
context = Object(context || window);
//要改变新的this 就要用context调用this方法 所以要把this方法放到context的属性上让context调用
const symbolFunc = Symbol(); //不可重复的变量
context.symbolFunc = this;
const result = context.symbolFunc(...args);//因为函数默认参数args会把args包装成数组,所以当调用MyCall传参时,如果传数组那么此时args就是[[args1,args2...]],如果传的是参数列表,那此时args就是[args1,args2...]
delete context.symbolFunc;
return result;
};
实现bind()
Function.prototype.MyBind = function(context){
if (!(typeof this === "function")) {
throw new TypeError(`${this} is not a function`);
}
context = Object(context || window);
const symbolFunc = Symbol();
context.symbolFunc = this;
return function(...args){
const result = context.symbolFunc(...args);
delete context.symbolFunc;
return result;
}
};
//注意在调用bind生成新函数时,如果传了其他参数,那么调用bind生成函数时传的参数会被放到后面
window.a = 'global'
let obj = {
a:'obj'
}
function conA(...args){
console.log(this.a)
console.log(args) //['argu1','argu2','argu3']
}
let newCon = conA.bind(obj,'argu1')
newCon('argu2','argu3')
- 补充
-
Object(arg)
// 如果给定值是 null 或 undefined,将会创建并返回一个空对象 console.log(Object(null)) //{...} // 如果传进去的是一个基本类型的值,则会构造其包装类型的对象 console.log(Object(123)) //123 控制台打印的是123 但本质上是Number(123) console.log(typeof Object(123)) //object // 如果传进去的是引用类型的值,仍然会返回这个值,这是一个浅拷贝
-
delete xxx
//用来删除对象的某属性,如果删除一个不存在的属性会没有效果但是也返回true //删除let var const声明的变量无效,并且返回false