js函数涉及到作用域时,函数定义时作用域以及很多东西无法确定,只有调用它时才能确定
作用是改变作用域,但是很多博客解释的非常复杂,这个解释比较清楚,直接上代码,上下两段代码等价。
function add(c,d) {
return this.a + this.b + c + d;
}
const obj = {a: 1, b: 2};
console.log(add.call(obj, 3, 4)); // 10
// 等价于
const o = {
a: 1,
b: 2,
add: function(c,d) {
return this.a + this.b + c + d;
}
};
console.log(o.add(3,4)) // 10
// 感觉相当于把add这个方法拉到obj这个作用域里来
apply和call区别在于apply第二个参数是Array,而call是将一个个传入,将第一段代码改写可得
function add(c,d) {
return this.a + this.b + c + d;
}
const obj = {a: 1, b: 2};
console.log(add.apply(obj, [3, 4])); // 10
// 或者
const e = [3, 4];
console.log(add.apply(obj, e)); // 10
bind 的作用和call很像,也会将它的第一个参数变成函数运行时的作用域对象,后边的参数作为函数的参数传入,但是它的独特型在于它会新建一个函数,上述的作用发生在这个新的函数被调用时,而且,当这个新函数作为构造函数时,它当时绑定的this对象(也就是刚刚的第一个参数)会失效,不过后边的参数依然有效。
function foo(c,d) {
this.b = 100;
console.log(this.a);
console.log(this.b);
console.log(c)
console.log(d)
}
var func = foo.bind({a: 1},'no.1')
func('no.2')
// 1
// 100
// no.1
// no.2
// 即使call也不能改变this
func.call({a: 2},'no3')
// 1
// 100
// no.1
// no.3
// 当 bind 返回的函数作为构造函数的时候,
// bind 时指定的 this 值会失效,但传入的参数依然生效。
// 所以使用func为构造函数时,this不会指向{a: 1}对象,this.a的值为undefined
new func('no.4')
类数组对象虽然可以访问到某个键值,但是却不能进行遍历
es5和es6都有各自的方法实现:
const list = document.getElementsByTagName('li')
console.log(Array.isArray(list)) // 不是数组
console.log(list[2].innerHTML) // 可以输出其下某个元素的值
console.log(list.forEach); // 无法进行遍历
// ES5方法将类数组对象数组化
var es5 = Array.prototype.slice.call(list)
// 或者使用 var es5 = [].slice.call(list)
console.log(es5)
// ES6方法将类数组对象数组化
var es6 = Array.from(list)
console.log(es6)
obj
是要定义新属性的对象
props
是新属性的名字
descriptor
是配置选项,含有:
configurable
是否可以重新定义
enumerable
是否可以枚举(object.keys())
value
初始值
writable
是否可以修改属性值
get
回调函数,初始计算得到当前属性
set
回调函数,监视当前属性值的变化
定义新属性时不能直接对象.属性这样去设置,应该使用Object.defineProperty(obj, prop, descriptor)
,需要注意的是:value
和writable
不能与get
set
同时使用,同时使用会报错:Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #
const obj = {
firstName: 'ma',
lastName: 'bo'
}
// 使用 value 和writable
Object.defineProperty(obj, 'fullName',{
configurable: true,
enumerable: true,
value: 'mo--b',
writable: true,
})
console.log(obj.fullName) // mo--b
const obj = {
firstName: 'ma',
lastName: 'bo'
}
// 使用get set
Object.defineProperty(obj, 'fullName',{
configurable: true,
enumerable: true,
get() { // 回调函数,初始计算得到当前属性
return this.firstName + this.lastName
},
set(value) { // 回调函数,监视当前属性值的变化
const names = value.split('--')
this.firstName = names[0]
this.lastName = names[1]
}
})
console.log(obj.fullName) // mabo
obj.fullName = 'lx--y'
console.log(obj.firstName, obj.lastName) // lx y
// 因为可枚举因此,若设置为不可枚举,则结果只有 ["firstName", "lastName"]
console.log(Object.keys(obj)) // ["firstName", "lastName", "fullName"]
判断吗obj自身有无prop属性
console.log(obj.hasOwnProperty('fullName' )) // true