函数名.name:函数名获取
函数表达式方式,获取匿名函数名称
var f=function (){
console.log(arguments.callee.name); // f 可以拿到匿名函数
console.log(f.name); // f
}
/*
es5会打印空“” 因为现在都是es6,所以看不到es5的情况
*/
console.log(f.name);//f
f();
函数表达式方式,获取函数名称
名字被第二个覆盖了,但调用时得调用第一个名字
var f = function fn() {
console.log(arguments.callee.name); // fn
console.log(f.name); // fn
}
console.log(f.name); // fn
f();
// fn();//ReferenceError: fn is not defined
new构造函数函数名字anonymous
// console.log(new Function.name);//TypeError: Function.name is not a constructor
console.log(new Function().name);//anonymous
console.log((new Function).name);//anonymous
bind与函数名
function foo(){}
console.log(foo.name);//foo
console.log(foo.bind({}).name);//bound foo
从 //TypeError: Cannot read properties of undefined (reading 'name')
对象的扩展:对象简写
属性变量名一致时可以简写
const foo="bar";
const baz={foo};
// const baz={foo:foo};
console.log(baz);//{ foo: 'bar' }
const foo="bar";
const baz={foo};
/*当属性名=变量名的时候可以简写
* foo等价于
* 属性名foo:变量名foo*/
// const baz={foo:foo};
console.log(baz);//{ foo: 'bar' }
function foo(a,b){
console.log({a,b});//{ a: 1, b: 2 }
console.log({a:a*2,b:b*2});//{ a: 2, b: 4 }
}
foo(1,2);
方法简写
const person={
age:'12',
say(){
console.log(this.age)
}
}
person.say()//12
箭头函数简写
/*function foo(a,b){
console.log({a,b});//{ a: 1, b: 2 }
console.log({a:a*2,b:b*2});//{ a: 2, b: 4 }
}
foo(1,2);*/
function foo(a=1,b=2){
return {a,b}
}
let foo=(a=1,b=2)=>{a,b};
解构赋值应用:包的导出与引用
导出
root.js
function foo() {
console.log(1)
}
function bar() {
console.log(2)
}
function baz() {
console.log(3)
}
let a = 3;
const obj = {
a,
foo,
bar,
baz
}
module.exports.obj=obj;
console.log(obj);
/*{
a: 3,
foo: [Function: foo],
bar: [Function: bar],
baz: [Function: baz]
}*/
引用
main.js引用
const obj=require('./root').obj;
console.log(obj);
/*{
a: 3,
foo: [Function: foo],
bar: [Function: bar],
baz: [Function: baz]
}
{
a: 3,
foo: [Function: foo],
bar: [Function: bar],
baz: [Function: baz]
}
*/
通过解构赋值拿到对象
// const obj=require('./root').obj;
/*通过解构赋值从obj拿到属性*/
// const {a:a,foo:foo,bar:bar,baz:baz}=require('./root').obj;
const {a, foo, bar, baz} = require('./root').obj;
console.log(a);//3
foo();//1
bar();//2
baz();//3
属性是字符串
var arr = [1, 23, 23, 45, 5];
/*属性会进行包装,把所有传入的值进行一个包装,变成字符串
* 定义的属性都是字符串*/
console.log(arr[1]);//23
console.log(arr["1"]);//23
const obj={
/* class(){
}*/
/*在对象中定义class方法,也可以,不冲突,但不推荐这样做
* 其实是把class变成字符串*/
"class":function (){
}
}
字符串可以用方法来利用它们
let obj={};
obj.foo=true;
console.log(obj);//{ foo: true }
/*拼接属性,通过表达式让属性拼接,变量相加减都是可以的*/
obj['f'+'o'+'o']=false;
console.log(obj);//{ foo: false }
通过字符串拼接成属性
属性名都会通过一种方式把它处理成字符串
let a='hello';
let b='world';
/*三句话都是给obj的helloworld属性赋值*/
let obj={
[a+b]:true,
['hello'+b]:123,
['hello'+'world']:undefined
}
console.log(obj);//{ helloworld: undefined }
[true]、[obj]属性的转换
通过原型上的方法转换成字符串,再从对象中查找属性(字符串)
与类型有关,Number、Boolean、对象Object、数组也是对象但是用Array
var myObject = {};
/*直接把true变成字符串*/
myObject[true] = 'foo';
myObject[3] = 'bar';
myObject[myObject] = 'baz';
console.log(myObject);//{ '3': 'bar', true: 'foo', '[object Object]': 'baz' }
console.log(myObject['true']);//foo
console.log(myObject['3']);//bar
console.log(myObject[myObject]);//baz
/*myObject对象被Object.prototype.toString方法转换成/[object Object]字符串,注意有[],
* 不是转换成myObject字符串*/
console.log(myObject['myObject']);//undefined
console.log(myObject['[object Object]']);//true
console.log(Boolean.prototype.toString.call(true));//true
console.log(Object.prototype.toString.call(myObject));//[object Object]
步骤类似于以下伪代码,对象[属性x],判断属性x的值进行不同的xxx.prototype.toString.call(x)转换
/*伪代码不能运行*/
var obj={};
obj[x]=1;
if(typeof x==='Number'){
obj[Number.prototype.toString.call(x)]=1;
}
else if(typeof(x)==='Boolean' ){
obj[Boolean.prototype.toString.call(x)]=1;
}
const a = {a: 1};
const b = {b: 2};
const obj={
[a]:'valueA',
[b]:'valueB'
}
console.log(obj);//{ '[object Object]': 'valueB' }
Array会用Array.prototype.toString转换
var myObject = {};
var arr = ['1', 2, 'san'];
myObject[arr] = 'arr';
console.log(myObject);//{ '1,2,san': 'arr' }
console.log(Object.prototype.toString.call(arr));//[object Array]
console.log(Array.prototype.toString.call(arr));//1,2,san
getOwnPropertyDescriptor检测属性特征的方法
es5之前js并没有提供一个直接检测属性特征的方法,比如检测一个属性是否是只读属性,是否可以遍历,这些属性在es5之前都没有
es5,属性描述符:可以理解成描述属性的键值对,属性:值,描述属性的对象
对象就是数据,方法也是数据,计算机一切都是数据,数据是,数据可以描述东西的
let obj={a:2};
console.log(Object.prototype);
getOwnPropertyDescriptor使用
Object.getOwnPropertyDescriptor(obj需要检测的对象 , ‘a‘对象中需要检测的属性) 查询obj中的a属性的特征
Object.getOwnPropertyDescriptor(obj,’a’)
参数一obj需要检测的对象
参数二’a’对象中需要检测的属性
return返回一个对象,对象里面有一系列数据,关于那个属性特征的数据,返回关于那个属性的描述符对象
用途:查询对象中的属性的描述符,特征
let obj={a:2};
// console.log(Object.prototype);
console.log(Object.getOwnPropertyDescriptor(obj,'a'));
configurable:(可配置的),通过defineProperty添加一个新的属性,或者修改一个已有属性
enumerable:(可枚举)
writable:(可写)
value:(值)
defineProperty给对象定义属性
是给对象定义属性的,配置修改的是属性,不是对象
Object.defineProperty(obj查询的对象, ‘a‘查询的属性,{描述符})
用途:通过obj、a查到属性,再通过对象(描述符),修改对象属性的特征
let obj = {};
Object.defineProperty(obj, 'a',{
value :2,
enumerable : true,
writable : true,
configurable : true
})
console.log(obj);//{a:2}
let obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
enumerable: true,
writable: true,
configurable: true
})
console.log(obj);//{a:2}
console.log(Object.getOwnPropertyDescriptor(obj, 'a'));
writable:(可写)设置为false,设置的属性不可以更改值
let obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
enumerable: true,
/*设置为false,不可以更改*/
writable: false,
configurable: true
})
obj.a=3;
/*es6在这里采取静默失败的策略,silenty field,属性没有生效,没有报错。
* 偷偷不执行这条语句*/
console.log(obj.a);//2
严格模式下报错
"use strict";
let obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
enumerable: true,
/*设置为false,不可以更改*/
writable: false,
configurable: true
})
obj.a=3;
//Uncaught TypeError: Cannot assign to read only property 'a' of object '#<Object>'
/*es6在这里采取静默失败的策略,silenty field,属性没有生效,没有报错。
* 偷偷不执行这条语句
* 用严格模式use strict会报错*/
console.log(obj.a);
但可以删除,虽然可以修改
// "use strict";
let obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
enumerable: true,
/*设置为false,不可以更改,但可以删除,严格模式下删除也不报错*/
writable: false,
configurable: true
})
console.log(obj);//{a: 2}
delete obj.a;
console.log(obj.a);//undefined
console.log(obj);//{}
configurable:(可配置的)设置为false,设置的属性不可删除
// "use strict";
let obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
enumerable: true,
writable: true,
/*configurable设置为false就不能删除了,configurable:false,不能删除;
* 但可以修改,writable设置为true,可以修改,*/
configurable: false
})
obj.a = 3;
console.log(obj);//{a: 3}
delete obj.a;
console.log(obj.a);//3
console.log(obj);//{a: 3}
getter,setter
1h19m
get操作,put操作
也是属性描述符,与writeable等一样,虽然打印只显示4个,但有没有显示的内容,比如getter等也是存在的
let obj={a:1};
obj.a;//[[Get]]操作
/**
* 当我们进行obj.a的时候,js引擎其实会通过[[Get]]来获取,
*属性的获取,[[Get]]没有特定设置,执行默认操作:查找当前属性如果没有,查找原型,
* */
obj.a=3;
/**
* 赋值操作[Put],[Put]默认操作,
* 1.getter;setter;
* 2.writable:false,不让你改:
* 3.赋值:
*
* time 1h27m35s
* 1看操作是否是getter、setter 2是否可写 3赋值
*/
getter setter
getter、setter改写获取属性的方式、设置属性的方式,
get方式重写了当前的获取属性的默认方式
var obj={
log:['example','test'],
get latest(){
if (this.log.length===0) {
return undefined;
}
return this.log[this.log.length-1];
}
}
console.log(obj.latest);//test
/*通过get方式重写了当前的获取属性的默认方式,obj.latest不再是之前原本的obj.a的方式来执行的,
* 它访问值的方式是通过get的方式来定义的*/
var obj={
log:['example','test'],
/**
* get latest()不是一个方法,而是一个属性,一个值,所以需要return返回一个值,
* 其实latest()本质上是一个方法,因为有get 所以必须有返回值,
* obj.latest是得到obj里面latest里面的值,本来会走[[Get]]的默认操作的,但我
* 通过get方式重写了获取属性的默认方式,现在获取latest属性值的方式是执行latest这个方法,
* 并把方法的返回值作为latest的属性值,而不是找有没有叫latest的属性,并获取它的值
* @returns {string|undefined}
*/
get latest(){
if (this.log.length===0) {
return undefined;
}
return this.log[this.log.length-1];
},
latest1(){
if (this.log.length===0) {
return undefined;
}
return this.log[this.log.length-1];
}
}
// console.log(obj.log)
console.log(obj.latest);//test
console.log(obj.latest1());//test
/*通过get方式重写了当前的获取属性的默认方式,obj.latest不再是之前原本的obj.a的方式来执行的,
* 它访问值的方式是通过get的方式来定义的*/
var obj={
log:['example','test'],
get latest(){
if (this.log.length===0) {
return undefined;
}
return this.log[this.log.length-1];
},
latest1(){
if (this.log.length===0) {
return undefined;
}
return this.log[this.log.length-1];
}
}
console.log(obj.latest);//test
console.log(obj.latest1());//test
/*通过get方式重写了当前的获取属性的默认方式,obj.latest不再是之前原本的obj.a的方式来执行的,
* 它访问值的方式是通过get的方式来定义的*/
time 1h38m
var myObject = {
get a() {
return 2;
}
}
Object.defineProperty(myObject, 'b', {
/*get与enumerable等都是可描述属性,只不过赋值需要给它赋值方法function,*/
get: function () {
// return this.a (2);
return this.a * 2;
},
enumerable: true,
/* value:6,
writable : true*/
/*都会报错,因为get已经有值了,已经是赋值语句,就不能在下面再给值了
* value、writeable这俩是不让用的,与get方式矛盾,起冲突
* configuable、enumerable可以用*/
})
console.log(myObject.a);//2 执行a()方法,return2,作为a的返回值
console.log(myObject.b);//4
time 1h46m
value与get冲突,不能都写
get、set可描述属性与value、writable属性不能同时存在
var myObject = {
get a() {
return 2;
}
}
Object.defineProperty(myObject, 'b', {
get: function () {
// return this.a (2);
return this.a * 2;
},
enumerable: true,
/* value:6,
writable : true*/
/*都会报错,因为get已经有值了,已经是赋值语句,就不能在下面再给值了
* value、writeable这俩是不让用的,与get方式矛盾,起冲突
* configuable、enumerable可以用*/
})
console.log(myObject.a);//2
console.log(myObject.b);//4
time 1h51m
set设置,必须给它一个值才能set,所以必须加参数,所有set都必须要有参数
var language = {
set current() {
},
log: []
}
time 1h53m
var language = {
set current(name) {
this.log.push(name);
},
log: []
}
language.current = 'EN';
console.log(language.log);//['EN']
分析
var language = {
set current(name) {
this.log.push(name);
},
log: []
}
/**
* 打印undefined,说明language.current = 'EN';不是给current这个属性赋值了,
* 不是默认的set操作了,而是执行current方法,current('EN'),把=的EN作为参数传过去,
* 执行方法,=号也不是默认的赋值操作了,而是传参,类似于传参,传了EN作为参数,
* 传参需要先指定是哪个方法,language.current找到是哪个方法,找到哪个方法并传参并执行,
* 执行了方法,所以log有值了
*/
language.current = 'EN';
console.log(language.current);//undefined
console.log(language.log);//['EN']
var language = {
set current(name) {
this.log.push(name);
},
log: []
}
language.current = 'EN';
language.current = 'FA';
console.log(language.log);//['EN', 'FA']
console.log(language.current);//undefined
console.log(language.current = 'TE');//TE
console.log(language.current);//undefined
console.log(language.log);//['EN', 'FA', 'TE']
var language = {
set current(name) {
this.log.push(name);
},
current1(name) {
this.log.push(name);
},
log: []
}
language.current = 'EN';
language.current = 'FA';
console.log(language.log);//['EN', 'FA']
console.log(language.current);//undefined
console.log(language.current = 'TE');//TE
/* language.current = 'EN'不是之前的赋值语句了,而是执行set current函数=“FA”,
* 就是current("FA")*/
console.log(language.current);//undefined
console.log(language.log);//['EN', 'FA', 'TE']
time 1h55m
obj.a=3;进行了赋值操作,我赋值再取值,obj.a还是走get a方法,返回2,值是不会改变的
var obj={
get a(){
return 2;
}
}
obj.a=3;
console.log(obj.a);//2
/*并不能等于3,一般有get属性,也得需要set属性,要不只能取值不能赋值,没有意义
* 一般get、set都是成对出现的*/
time 1h56m27s
所以我需要get、set方法同时使用
get返回值不能写死,如果get就返回2,就永远取值时走get方法得到2
a属性的get方法、set方法
var obj={
get a(){
return 2;
},
set a(val){
// return this.a*2;//3
return val*2;//3
}
}
console.log(obj.a=3);//3
console.log(obj.a);//2
time 2h
var obj={
get a(){
// return 2;
return this._a;
},
set a(val){
// return this.a*2;//3
// return val*2;//3
this._a=val*2;
}
}
console.log(obj.a=3);//3
console.log(obj.a);//6
这个是get、set比较基本的用法,这个之后去练习
var obj={
get a(){
// return 2;
return this._a;
},
set a(val){
// return this.a*2;//3
// return val*2;//3
this._a=val*2;
}
}
/**
* 赋值,走a的set方法,this._a=3*2=6
*/
console.log(obj.a=3);//3
/**
* 取值,走a的get方法,return this._a,return 6,结果是6
*/
console.log(obj.a);//6
time 2h2m
getter、setter操作,覆盖了原本的[[Get]]、[[Put]]操作